android影音

Android相机<第三篇>:Camera详解

2019-09-16  本文已影响0人  NoBugException

当我们自定义相机时,常常使用Camera对象完成拍照流程,本文的重点在于研究Camera 各个方法的作用。

[方法一] 获取Camera对象

Camera mCamera = Camera.open();

[方法二] 拍照

public final void takePicture(ShutterCallback shutter, PictureCallback raw, PictureCallback postview, PictureCallback jpeg)

使用方法如下:

    mCamera.takePicture(null, null, null, new Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {

        }
    });

它有一个回调,拍完照片之后会执行onPictureTaken回调方法,data参数为图片的字节数组。

[方法三] 自动聚焦

自动聚焦的监听必须放在启动预览界面(mCamera.startPreview())之后,否则部分手机会崩溃。

实现代码如下:

    //自动获取焦点
    mCamera.autoFocus(autoFocusCallback );
private Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
    @Override
    public void onAutoFocus(boolean success, Camera camera) {

    }
};

此时发现,自动聚焦的回调方法始终只执行一次,那么怎么做才能无限聚焦呢?只要在自动聚焦的回调方法中添加两句代码即可。

private Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
    @Override
    public void onAutoFocus(boolean success, Camera camera) {
        mCamera.cancelAutoFocus();
        camera.autoFocus(autoFocusCallback);
    }
};

与设置自动聚焦相比,还有一个方法取消自动聚焦cancelAutoFocus

以上是实现自动聚焦的其中一个方法,当然还有其它方法,文章下面会介绍。

[方法四] 锁定、解锁、重连

//锁定摄像机硬件资源
mCamera.lock();
//解锁摄像机硬件资源
mCamera.unlock();
//重连
mCamera.reconnect();

为了防止相机被其它资源利用,相机默认是锁定状态。当其它资源想要利用相机时,必须解锁和重连后才能继续使用相机服务。

如果仅仅使用拍照,您可能不需要使用这三个方法,当使用MediaRecorder录制时会使用这三个方法获取相机服务。

[方法五] 设置预览方向

mCamera.setDisplayOrientation(90);

预览方向默认是横屏的,所以这里要调整一下预览方向。

[方法六] 设置预览界面

目前拍照涉及到的预览界面主要有两种:TextureViewSurfaceView

        mCamera.setPreviewDisplay(SurfaceHolder);
        mCamera.setPreviewTexture(SurfaceTexture);

有关TextureViewSurfaceView会在第四篇第五篇介绍。

[方法七] 设置预览监听

        mCamera.setPreviewCallback(new Camera.PreviewCallback() {
            @Override
            public void onPreviewFrame(byte[] data, Camera camera) {
                
            }
        });

这个监听最强大的地方在于可以不停的返回一帧画面的图像数据,可以利用OpenGL对图片进行处理。

设置监听的方法还有一个,如下:

        mCamera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {
            @Override
            public void onPreviewFrame(byte[] data, Camera camera) {
                
            }
        });

这个方法应该是和mCamera.addCallbackBuffer(byte[] callbackBuffer)一起使用,mCamera.addCallbackBuffer(byte[] callbackBuffer)是向缓存队列中添加一个预览帧。

这两种监听的工作方式差不多,他们都会不停的回调当前预览帧,那么如果获取拍照或者触发聚焦时的预览帧的话,就会使用以下预览监听方案:

        mCamera.setOneShotPreviewCallback(new Camera.PreviewCallback() {
            @Override
            public void onPreviewFrame(byte[] data, Camera camera) {

            }
        });

如果处于预览状态,那么会立即回调一个预览帧。

当触发聚焦时,此时的画面最为清晰,可以使用这个监听获取当前预览帧,根据回调返回的字节数组来处理图像。

[方法八] 开始预览和停止预览

当Camera绑定预览界面后,Camera就可以启动预览界面和停止预览界面。

//启动预览界面
mCamera.startPreview();

//停止预览界面
mCamera.stopPreview();

只有启动预览界面之后,预览监听才会收到回调。

[方法九] 平滑缩放

有些手机的相机自带缩放功能,当我们用双指缩放预览界面时会触发平滑缩放监听。当然,一些手机不支持平滑缩放功能。

监听代码如下:

        mCamera.setZoomChangeListener(new Camera.OnZoomChangeListener() {
            @Override
            public void onZoomChange(int zoomValue, boolean stopped, Camera camera) {
                
            }
        });

zoomValue为当前缩放因子,stopped表示当前缩放是否结束,如果为false则表示缩放正在进行,如果为true表示缩放结束。

调用startSmoothZoom方法后开始启动平滑缩放功能,代码如下:

        Camera.Parameters parameters = mCamera.getParameters();
        if(parameters.isSmoothZoomSupported()){
            mCamera.startSmoothZoom(1);
        }

startSmoothZoom方法传递一个数值,这个数值就是缩放因子,它的取值范围是:[0,parameters.getMaxZoom()],取值不可超过这个范围,否则报错,在设置缩放因子之前必须先判断手机是否支持平滑缩放,否则设置无效或者异常,设置缩放因子后,缩放监听开始执行。假设当前缩放因子为0,那么执行以下语句:

        if(parameters.isSmoothZoomSupported()){
            mCamera.startSmoothZoom(12);
        }

那么,它不会直接从0变成12,设置缩放因子需要消耗一定的时间,它的变化过程如下:

也就是说,平滑缩放的监听回调执行了12次。

在这个过程中,可以提前停止缩放,只要执行这个方法即可

    mCamera.stopSmoothZoom();

startSmoothZoomstopSmoothZoom这两个方法必须在启动预览界面(mCamera.startPreview())之后执行,否则会报错。

[方法十] 相机异常监听

        mCamera.setErrorCallback(new Camera.ErrorCallback() {
            @Override
            public void onError(int error, Camera camera) {
                switch (error){
                    case Camera.CAMERA_ERROR_UNKNOWN:
                        System.out.println("相机未知错误");
                        break;
                    case Camera.CAMERA_ERROR_EVICTED:
                        System.out.println("相机已断开连接");
                        break;
                    case Camera.CAMERA_ERROR_SERVER_DIED:
                        System.out.println("媒体服务器死机");
                        break;
                    default:
                        System.out.println("未知异常error:"+error);
                        break;

                }
            }
        });

可以监听相机使用过程之的错误。

[方法十一] 设置拍照后,存入本地图片的格式

        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPictureFormat(ImageFormat.JPEG);
        mCamera.setParameters(parameters);

setPictureFormat可以设置图片格式。

[方法十二] 解决输出图片旋转90度问题

        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setRotation(90);
        mCamera.setParameters(parameters);

[方法十三] 设置预览大小和图片大小

设置预览大小就是设置预览界面的显示图像的分辨率

        Camera.Parameters parameters = mCamera.getParameters();
        Camera.Size previewSize = getCameraSize(parameters.getSupportedPreviewSizes(), width, height);
        parameters.setPreviewSize(previewSize.width, previewSize.height);
        mCamera.setParameters(parameters);

设置图片大小就是设置保存到本地的图片分辨率

        Camera.Parameters parameters = mCamera.getParameters();
        Camera.Size pictureSize = getCameraSize(parameters.getSupportedPictureSizes(), width, height);
        parameters.setPictureSize(pictureSize.width, pictureSize.height);
        mCamera.setParameters(parameters);

其中getCameraSize方法就是筛选出最适合的分辨率。

/**
 * 获取最合适的Size
 * @param sizeList
 * @param width
 * @param height
 * @return
 */
private Camera.Size getCameraSize(List<Camera.Size> sizeList, int width, int height){

    Camera.Size tempSize = null;
    float aspectRatio = height * 1.0f / width;//求出预期横宽比
    float offset = aspectRatio;//预期横宽比和实际横宽比误差

    for(Camera.Size size : sizeList){

        if(size.width < height || size.height < width){
            continue;
        }

        //误差最小值
        if(Math.abs(aspectRatio - size.width * 1.0f / size.height) < offset){
            offset = Math.abs(aspectRatio - size.width * 1.0f / size.height);
            tempSize = size;
        }
    }

    if(tempSize == null){
        tempSize = sizeList.get(0);
    }


    return tempSize;
}

[方法十四] 聚焦模式

Camera.Parameters parameters = mCamera.getParameters();
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
mCamera.setParameters(parameters);

调用setFocusMode方法可以设置聚焦模式,聚焦模式有很多:

FOCUS_MODE_AUTOFOCUS_MODE_INFINITYFOCUS_MODE_MACROFOCUS_MODE_FIXEDFOCUS_MODE_EDOFFOCUS_MODE_CONTINUOUS_VIDEOFOCUS_MODE_CONTINUOUS_PICTURE,这些模式用到的有两种模式,分别是:FOCUS_MODE_CONTINUOUS_PICTUREFOCUS_MODE_CONTINUOUS_VIDEO

这两个参数最大的作用是可以不断的触发聚焦,并且可以接收到监听的回调。

        mCamera.setAutoFocusMoveCallback(new Camera.AutoFocusMoveCallback() {
            @Override
            public void onAutoFocusMoving(boolean start, Camera camera) {
                
            }
        });

监听setAutoFocusMoveCallback与聚焦模式结合使用可以实现随时聚焦功能,类似于[方法三]中说到的自动聚焦,但是autoFocus不可以和setAutoFocusMoveCallback混用,有些手机混用是没有问题的,但是有些手机一旦触发了autoFocus监听,那么setAutoFocusMoveCallback监听就会中断,所以这两个触发聚焦功能只能选择一个。

代码实现如下:

        mCamera.setAutoFocusMoveCallback(new Camera.AutoFocusMoveCallback() {
            @Override
            public void onAutoFocusMoving(boolean start, Camera camera) {

            }
        });
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);     

//或者     
//parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);

[方法十五] 拍照声音

enableShutterSound方法可以打开拍照声音,如下:

        mCamera.enableShutterSound(true);

true为打开拍照声音,false为关闭拍照声音。

不过,有一点需要注意

    //拍照
    mCamera.takePicture(null, null, null, new Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {

        }
    });

如果takePicture的第一个参数为null,那么不管怎么设置enableShutterSound都不会有拍照声音。

    //拍照
    mCamera.takePicture(new Camera.ShutterCallback() {
        @Override
        public void onShutter() {
            
        }
    }, null, null, new Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {

        }
    });

如上代码,保证第一个参数不为空,这样enableShutterSound才能保证有效。

[方法十六] 人脸检测

自从Android 6.0开始,Android就开始支持人脸识别功能。

设置面部识别监听:

        mCamera.setFaceDetectionListener(new Camera.FaceDetectionListener() {
            @Override
            public void onFaceDetection(Camera.Face[] faces, Camera camera) {
                if(faces != null && faces.length > 0){

                }
            }
        });

开始面部识别:

        mCamera.startFaceDetection();

停止面部识别:

        mCamera.stopFaceDetection();

[方法十七] 释放相机资源

mCamera.release();

请注意,一旦释放了相机资源,想要重启相机时必须重新执行以下代码:

Camera mCamera = Camera.open();
说明

另外,Camera.Parameters还有需要参数都没有讲到,因为感觉只要说明一下常用的即可。在Andorid5.0开始,Camera已被废弃,改为Camera2Camera2将会在后面章节会讲到。

[本章完...]

上一篇下一篇

猜你喜欢

热点阅读