Android之直播宽高比和相机宽高比不支持后动态获取所支持的宽高比

场景:

直播设置采集宽高 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);
    }
}
```
```
相关推荐
Kapaseker1 天前
Compose 进阶—巧用 GraphicsLayer
android·kotlin
黄林晴1 天前
Android17 为什么重写 MessageQueue
android
阿巴斯甜2 天前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker2 天前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95272 天前
Andorid Google 登录接入文档
android
黄林晴2 天前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab2 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿3 天前
Android MediaPlayer 笔记
android
Jony_3 天前
Android 启动优化方案
android
阿巴斯甜3 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android