相机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大小的,但是有些手机并没有这一尺寸 所以在保存时我会遍历手机支持的尺寸,保存第一个大于这一尺寸最接近的一个。
在三星手机上尺寸是这样的:
没错,尺寸是由大到小排列的,因此保存的是最大的这个尺寸,导致保存图片时图片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);
这样就OK了。