场景:
直播设置采集宽高 360p 360x640 但是手机相机不支持,所以出现裁剪(脸大问题)
解决方案:
获取手机相机支持的宽高尺寸 ,根据需要设置的宽高动态匹配接近的宽高比 阈值要设置好
arduino
阀值 0.2
val size = CameraSizeHelper.getInstance().getOptimalSize(context, config.captureWidth, config.captureHeight)
// 接近的宽高
val w=size.getWidth()
val w=size.getHeight()
ini
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.*;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.util.Log;
import android.util.Size;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
/**
* 改进版 CameraSizeHelper
* 支持向上枚举 + 比例误差阈值可配置
*/
public class CameraSizeHelper {
private static volatile CameraSizeHelper instance;
private CameraSizeHelper() {}
public static CameraSizeHelper getInstance() {
if (instance == null) {
synchronized (CameraSizeHelper.class) {
if (instance == null) {
instance = new CameraSizeHelper();
}
}
}
return instance;
}
/**
* 获取最接近目标尺寸的相机预览尺寸
* @param context 上下文
* @param targetWidth 目标宽度
* @param targetHeight 目标高度
* @param ratioThreshold 比例误差阈值,例如0.2
* @return 最合适的支持尺寸
*/
public Size getOptimalSize(Context context, int targetWidth, int targetHeight, double ratioThreshold) {
try {
CameraManager cm = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
String cameraId = null;
// 找后置摄像头
for (String id : cm.getCameraIdList()) {
CameraCharacteristics characteristics = cm.getCameraCharacteristics(id);
Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (facing != null && facing == CameraCharacteristics.LENS_FACING_BACK) {
cameraId = id;
break;
}
}
if (cameraId == null) return new Size(targetWidth, targetHeight);
CameraCharacteristics cc = cm.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = cc.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (map == null) return new Size(targetWidth, targetHeight);
Size[] sizes = map.getOutputSizes(SurfaceTexture.class);
if (sizes == null || sizes.length == 0) return new Size(targetWidth, targetHeight);
boolean portrait = targetHeight > targetWidth;
double targetRatio = (double) targetHeight / targetWidth;
// 0. 完全匹配优先
for (Size s : sizes) {
int w = portrait && s.getWidth() > s.getHeight() ? s.getHeight() : s.getWidth();
int h = portrait && s.getWidth() > s.getHeight() ? s.getWidth() : s.getHeight();
if (w == targetWidth && h == targetHeight) {
return new Size(w, h);
}
}
// 1. 将所有尺寸按宽度升序排列(竖屏)
List<Size> sortedSizes = new ArrayList<>();
for (Size s : sizes) {
int w = portrait && s.getWidth() > s.getHeight() ? s.getHeight() : s.getWidth();
int h = portrait && s.getWidth() > s.getHeight() ? s.getWidth() : s.getHeight();
sortedSizes.add(new Size(w, h));
}
sortedSizes.sort(Comparator.comparingInt(Size::getWidth));
// 2. 从目标宽度向上枚举
Size best = null;
double minDiff = Double.MAX_VALUE;
for (int i = 0; i < sortedSizes.size(); i++) {
Size s = sortedSizes.get(i);
if (s.getWidth() < targetWidth) continue; // 向上枚举
double ratio = (double) s.getHeight() / s.getWidth();
double diff = Math.abs(ratio - targetRatio);
if (diff <= ratioThreshold) { // 阈值内直接返回
return s;
} else {
// 记录最小比例差的候选
if (diff < minDiff) {
minDiff = diff;
best = s;
}
}
}
// 3. 如果向上找不到阈值内的,返回最小比例差的向上尺寸
if (best != null) return best;
// 4. 否则返回最大尺寸(兜底)
return sortedSizes.get(sortedSizes.size() - 1);
} catch (Exception e) {
Log.e("CameraSizeHelper", "getOptimalSize failed", e);
return new Size(targetWidth, targetHeight);
}
}
/**
* 默认阈值调用
*/
public Size getOptimalSize(Context context, int targetWidth, int targetHeight) {
return getOptimalSize(context, targetWidth, targetHeight, 0.2);
}
}
```
```