自定义相机踩过的坑

通用的问题

因为我要做的是一个高度定制(只有前置摄像头并且整个项目activity都是禁止翻转的)的相机,相机的surfaceview的宽度和高度都不是屏幕的高度和宽度,所以相机的preview(预览)和picture(拍照)都会有问题,有时候发现preview中的图像变形,或者拍出来的照片及其模糊,还有一些其他问题。今天把做这个项目中遇到的坑都给趴出来。

setPreviewSize和setPictureSize
之前做法,paramerters.getSupportedPreviewSizes和parameters.getSupportedPictureSizes,获取一个list,从里面找出最大的widthheight,然后设置setPreviewSize和setPictureSize,这种情况,对于surfaceview是全屏的情况下,是没发现什么问题的。但是如果surfaceview不是全屏的情况下呢?
这种情况,找到一种最合适的解决方案,算出surfaceview的width/height,然后遍历整个paramerters.getSupportedPreviewSizes和parameters.getSupportedPictureSizes的width/height,找出最接近的比例,这就是最核心的算法。
好了,算法找出来之后,我们就要开始进一步优化了。
遇到过的坑:
1)好了,算法写好了,我们就开始测试了,发现相机预览的时候,图像还是有拉伸,这是为什么咧?
为了解决这个问题,我把所有的支持的preview的图片全都打印出来,发现其中有很多size,width > height,而我们的surfaceview是width < height,这是一个坑,所以我们在进行核心算法之前,我们要遍历list,目的是要先将获取的previewsize的list中的size中的width和height全部变成width > height,然后返回一个我们需要在后面算法遍历的list。同理,picturesize也是要同样处理。
2)使用上面新的算法的时候,发现预览的时候,发现特别模糊。
这个原因,一下就可以猜测到,我们选取preview size的时候,虽然找到最接近sufaceview的width/height,但是这个像素点太低了。所以我又将support preview size以及width/height又给打了一遍,发现其实有两个size是比例相近的,其中一个size像素比较高,但是为啥选了低的那个咧?
很明显,这个support list是乱序的,选到一个最合适的,就是它了。所以,开始还需要将这个list排序一波,从大到小,这样的话,就算list中有好几个比例最接近sufaceview的,我们也是找到最大像素的size。同时呢,为了防止图片像素太低,我又加了一个判断,少于480
320(实验得到的),就可以直接break出来了,这样也能保证比较高的像素点,还能减少时间复杂度。
3)遗留问题,三星
三星拍出来的照片是反的,开始以为是width>heigth的原因,验证得到,setRoutation失败。
开始以为是preview和picture的width>height,然后就在想改变surfaceview或者其他方法,后来发现,其他手机width>height,最终才知道,原来是三星手机setRoutation没作用。
至今没有解决。

个别手机问题

设置自动对焦

好了,设置好preview和picture的size之后,图像就不会出现变形或者其他状况了,但是我们发现这样的话,看起来模糊,这是为啥咧?原来我们没有设置自动对焦,好,那我们就设置自动对焦,这样又趴出阿里一些坑,而且都是个别手机的问题。
我们都知道设置自动对焦代码如下:

1
2
3
4
5
6
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean b, Camera camera) {
}
});

好了,然后我们就用手机测试一波。

三星手机

出现了这个问题:
这里写图片描述

三星手机,在执行,autofus方法的时候崩溃了(这里涉及到native中的代码,太难了,所以没有去看源码)。当时猜测可能是相机还没完全初始化好,就开始自动对焦,就会崩溃,所以这个方法延时两秒执行,然后就可以了。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
handler.postDelayed(new Runnable() {
@Override
public void run() {
try {
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean b, Camera camera) {
}
});
} catch (RuntimeException e) {
e.printStackTrace();
}
}
}, 2000);

这是我一开始的解决方法,后来又查找了一些资料,发现官方介绍文档的时候,说要将autoFocus放到startPreview之后,takePicture之前,结果自己试了一波,果然是这个原因。所以这样的话,我们就不要延时了,放到startPreview之后:

1
2
3
4
5
6
7
8
9
10
11
mCamera.startPreview();
try {
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean b, Camera camera) {
}
});
} catch (RuntimeException e) {
e.printStackTrace();
}

猜测原因:
部分手机camera初始化耗时长,还没初始好,就设置自动对焦可能就出现问题了。自动对焦延时对焦,对相机来说没有什么影响,所以这种方法可以适用于其他手机类型。

小米手机
红米米手机设置parameters.setFocusMode自动对焦,会直接蹦掉。log如下:
这里写图片描述

这个log根本看不出问题出在哪里,不过幸好的时候,我直接没有设置过自动对焦,而且小米手机没有发生过崩溃,所以就大胆猜测这个问题出在设置自动对焦的时候,最终定位到setFocusMode方法中。
做了如下处理:(红米手机所支持的FoucusMode的类型中,没有auto类型,所以setParameters的时候会出错)

1
2
3
4
5
6
7
List<String> focusModes = parameters.getSupportedFocusModes();
for (String mode : focusModes) {
if (mode.equals(Camera.Parameters.FOCUS_MODE_AUTO)) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
break;
}
}