相机api

        Camera:最主要的类,用于管理和操作camera资源。它提供了完整的相机底层接口,支持相机资源切换,设置预览/拍摄尺寸,设定光圈、曝光、聚焦等相关参数,获取预览/拍摄帧数据等功能,主要方法有以下这些:

  • open():获取camera实例。
  • setPreviewDisplay(SurfaceHolder):绑定绘制预览图像的surface。surface是指向屏幕窗口原始图像缓冲区(raw buffer)的一个句柄,通过它可以获得这块屏幕上对应的canvas,进而完成在屏幕上绘制View的工作。通过surfaceHolder可以将Camera和surface连接起来,当camera和surface连接后,camera获得的预览帧数据就可以通过surface显示在屏幕上了。
  • setPrameters设置相机参数,包括前后摄像头,闪光灯模式、聚焦模式、预览和拍照尺寸等。
  • startPreview():开始预览,将camera底层硬件传来的预览帧数据显示在绑定的surface上。
  • stopPreview():停止预览,关闭camra底层的帧数据传递以及surface上的绘制。
  • release():释放Camera实例
  • takePicture(Camera.ShutterCallback shutter, Camera.PictureCallback raw, Camera.PictureCallback jpeg):这个是实现相机拍照的主要方法,包含了三个回调参数。shutter是快门按下时的回调,raw是获取拍照原始数据的回调,jpeg是获取经过压缩成jpg格式的图像数据的回调。

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

        SurfaceHolder:surfaceholder是控制surface的一个抽象接口,它能够控制surface的尺寸和格式,修改surface的像素,监视surface的变化等等,surfaceholder的典型应用就是用于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,从而实时显示相机预览图像。
  • surfaceDestroyed(SurfaceHolder holder):在surface销毁之前被调用。在开发自定义相机时,可以通过重载这个函数调用camera.stopPreview(),camera.release()来实现停止相机预览及释放相机资源等操作


在自定义相机时遇到的问题:

1:在竖屏拍照时相机预览和得到的图片被旋转90°。

原因:因为相机默认的取景方向是横屏,因此在竖屏方向得到的图片是被旋转90°的。

解决:应该想办法让相机的预览方向和相机得到的图片方向一致。

(1):可以将相机的预览方向旋转90°,这样预览和得到的图片就一致了。但是这样在测试时出现了一种情况在部分机型上例如华为的p8上 出现图片左右镜像的问题,而在其他机型上正常。

(2):将得到的图片旋转90°。正常运行,没有问题。

public static Bitmap rotate(Bitmap b, int degrees) {
        if (degrees != 0 && b != null) {
            Matrix m = new Matrix();
//          m.postRotate(90);
            m.setRotate(degrees,(float) b.getWidth()/2,(float) b.getHeight()/2);
            try {
                Bitmap b2 = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), m, true);
                if (b != b2) {
                    b.recycle();
                    b = b2;
                }
            } catch (Exception ex) {
                Log.i(TAG,ex.getMessage());
                // We have no memory to rotate. Return the original bitmap.
            }
        }
        return b;
    }

2:在使用三星手机测试时 拍照结束 图片保存到本地时特别容易崩溃。

原因:再通过与其他机型对比发现,三星手机保存图片时明显慢于其他机型,后来通过打印log发现一个问题。

因为我保存图片时想保存1920*1080大小的,但是有些手机并没有这一尺寸 所以在保存时我会遍历手机支持的尺寸,保存第一个大于这一尺寸最接近的一个。

在三星手机上尺寸是这样的:

Android SurfaceView 相机预览旋转摄像头角度 surface怎么调前后摄像_自定义相机

没错,尺寸是由大到小排列的,因此保存的是最大的这个尺寸,导致保存图片时图片IO过长,因此修改图片代码,

int x = 0;
int y = 0;
int x1 = 0;
int y1 = 0;
for (int i=0;i<params.getSupportedPictureSizes().size();i++){
    if(1920<=params.getSupportedPictureSizes().get(i).width&&1080<=params.getSupportedPictureSizes().get(i).height){
        x = params.getSupportedPictureSizes().get(i).width;
        y = params.getSupportedPictureSizes().get(i).height;
        break;
    }
}
for (int i=params.getSupportedPictureSizes().size()-1;i>0;i--){
    if(1920<=params.getSupportedPictureSizes().get(i).width&&1080<=params.getSupportedPictureSizes().get(i).height){
        x1 = params.getSupportedPictureSizes().get(i).width;
        y1 = params.getSupportedPictureSizes().get(i).height;
        break;
    }
}
if(x>x1){
    x = x1;
    y = y1;
}
params.setPictureSize(x,y);



Android SurfaceView 相机预览旋转摄像头角度 surface怎么调前后摄像_帧率_02

这样就OK了。