参数设置
Camera.Parameters param = camera.getParameters();
param.setPreviewSize(width, height);
width一般大于height,默认摄像头是横向,预览时需要设置camera.setDisplayOrientation(90);
预览大小
常见的分辨率为4:3,或者16:9,即640x480和1280x720
Android6.0的源代码中,预览的大小和PictureSize有关,先看看系统如何设置Picture Size
PictureSize设置
public static void initialCameraPictureSize(
Context context, Parameters parameters) {
// When launching the camera app first time, we will set the picture
// size to the first one in the list defined in "arrays.xml" and is also
// supported by the driver.
List supported = parameters.getSupportedPictureSizes();
if (supported == null) return;
for (String candidate : context.getResources().getStringArray(
R.array.pref_camera_picturesize_entryvalues)) {
if (setCameraPictureSize(candidate, supported, parameters)) {
SharedPreferences.Editor editor = ComboPreferences
.get(context).edit();
editor.putString(KEY_PICTURE_SIZE, candidate);
editor.apply();
return;
}
}
Log.e(TAG, "No supported picture size found");
}
读取预先pref_camera_picturesize_entryvalues配置大小,然后在和设备支持的尺寸匹配,两个相同的作为pictureSize;并保存。
R.array.pref_camera_picturesize_entryvalues 中值为
- 3264x2448
- 2592x1944
- 2592x1936
- 2560x1920
- 2048x1536
- 1600x1200
- 1280x960
- 1024x768
- 640x480
- 320x240
setCameraPictureSize 方法比较预先设置的之中是否有设置支持的大小相等的值
public static boolean setCameraPictureSize(
String candidate, List supported, Parameters parameters) {
int index = candidate.indexOf('x');
if (index == NOT_FOUND) return false;
int width = Integer.parseInt(candidate.substring(0, index));
int height = Integer.parseInt(candidate.substring(index + 1));
for (Size size : supported) {
if (size.width == width && size.height == height) {
parameters.setPictureSize(width, height);
return true;
}
}
return false;
}
预览大小设置
系统Camera设置
系统相机预览大小的设置和picturesize有关。
在startPreview中会调用updateCameraParametersPreference()方法
// Set the preview frame aspect ratio according to the picture size.
Size size = mParameters.getPictureSize();
mPreviewPanel = findViewById(R.id.frame_layout);
mPreviewFrameLayout = (PreviewFrameLayout) findViewById(R.id.frame);
mPreviewFrameLayout.setAspectRatio((double) size.width / size.height);
// Set a preview size that is closest to the viewfinder height and has
// the right aspect ratio.
List sizes = mParameters.getSupportedPreviewSizes();
Size optimalSize = Util.getOptimalPreviewSize(this,
sizes, (double) size.width / size.height);
Size original = mParameters.getPreviewSize();
if (!original.equals(optimalSize)) {
mParameters.setPreviewSize(optimalSize.width, optimalSize.height);
// Zoom related settings will be changed for different preview
// sizes, so set and read the parameters to get lastest values
mCameraDevice.setParameters(mParameters);
mParameters = mCameraDevice.getParameters();
}
调用Util.getOptimalPreviewSize()方法获取合适previewSize,
public static Size getOptimalPreviewSize(Activity currentActivity,
List sizes, double targetRatio) {
// Use a very small tolerance because we want an exact match.
final double ASPECT_TOLERANCE = 0.001;
if (sizes == null) return null;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
// Because of bugs of overlay and layout, we sometimes will try to
// layout the viewfinder in the portrait orientation and thus get the
// wrong size of preview surface. When we change the preview size, the
// new overlay will be created before the old one closed, which causes
// an exception. For now, just get the screen size.
//获取屏幕大小
Point point = getDefaultDisplaySize(currentActivity, new Point());
//相机默认横屏,高度是两者中最小的一个
int targetHeight = Math.min(point.x, point.y);
// Try to find an size match aspect ratio and size
for (Size size : sizes) {
double ratio = (double) size.width / size.height;
//相机支持的比率和targetRatio相差太大时,继续查找
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
//比率满足时,高度不能差太多
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
// Cannot find the one match the aspect ratio. This should not happen.
// Ignore the requirement.
if (optimalSize == null) {
Log.w(TAG, "No preview size match the aspect ratio");
minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
根据targetRatio,和实际屏幕大小来选择SupportedPreviewSizes中合适的值。targetRatio我觉得也可以使用屏幕比例。
Zing中previewSize设置
initFromCameraParameters()方法会调用findBestPreviewSizeValue()方法获取适合的大小;screenResolution为屏幕大小
//private static final int MIN_PREVIEW_PIXELS = 320 * 240; // small screen
//private static final int MAX_PREVIEW_PIXELS = 800 * 480; // large/HD screen
private static Point findBestPreviewSizeValue(Camera.Parameters parameters,
Point screenResolution,
boolean portrait) {
Point bestSize = null;
int diff = Integer.MAX_VALUE;
for (Camera.Size supportedPreviewSize : parameters.getSupportedPreviewSizes()) {
int pixels = supportedPreviewSize.height * supportedPreviewSize.width;
//预先设置大小
if (pixels < MIN_PREVIEW_PIXELS || pixels > MAX_PREVIEW_PIXELS) {
continue;
}
int supportedWidth = portrait ? supportedPreviewSize.height : supportedPreviewSize.width;
int supportedHeight = portrait ? supportedPreviewSize.width : supportedPreviewSize.height;
//不太理解为啥要交叉相乘,总之是比较差值
int newDiff = Math.abs(screenResolution.x * supportedHeight - supportedWidth * screenResolution.y);
if (newDiff == 0) {
bestSize = new Point(supportedWidth, supportedHeight);
break;
}
//更新最小差值
if (newDiff < diff) {
bestSize = new Point(supportedWidth, supportedHeight);
diff = newDiff;
}
}
//如果还没找到,就使用预览值
if (bestSize == null) {
Camera.Size defaultSize = parameters.getPreviewSize();
bestSize = new Point(defaultSize.width, defaultSize.height);
}
return bestSize;
}
zxing中是根据实际屏幕值,根设备支持的尺寸交叉相乘,获取差值最小设为最合适的值,如果没有使用预览值。
zxing使用方法比较简单些。