package com.erlei.videorecorder.camera; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Configuration; import android.graphics.ImageFormat; import android.graphics.Rect; import android.graphics.SurfaceTexture; import android.os.Handler; import android.os.Looper; import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; import android.view.Surface; import android.view.SurfaceHolder; import android.view.WindowManager; import com.erlei.videorecorder.camera.annotations.Antibanding; import com.erlei.videorecorder.camera.annotations.ColorEffect; import com.erlei.videorecorder.camera.annotations.Facing; import com.erlei.videorecorder.camera.annotations.FlashModel; import com.erlei.videorecorder.camera.annotations.FocusModel; import com.erlei.videorecorder.camera.annotations.PictureFormat; import com.erlei.videorecorder.camera.annotations.PreviewFormat; import com.erlei.videorecorder.camera.annotations.SceneModel; import com.erlei.videorecorder.camera.annotations.WhiteBalance; import com.erlei.videorecorder.util.Config; import com.erlei.videorecorder.util.LogUtil; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; /** * Created by lll on 2018/1/18. * 相机工具类 */ @SuppressWarnings({"WeakerAccess", "unused"}) public class Camera { private static final String S_CAMERA_SUPPORTED_MODES = "camera_supported_modes"; private final SparseArray<HashMap<String, String>> mSupportedModes = new SparseArray<>(); /** * android.hardware.Camera#getNumberOfCameras() == 0 */ public static final int NO_CAMERA = 1; /** * CameraBuilder == null , 不应该发生 */ public static final int NOT_CONFIGURED = 2; /** * 设置的相机朝向设备不支持 * * @see CameraBuilder#setFacing(int) */ public static final int UNSUPPORTED_FACING = 3; /** * 打开相机失败 (请检查权限) * * @see android.hardware.Camera#open() */ public static final int OPEN_ERROR = 4; /** * 成功连接相机服务并开启预览 */ public static final int SUCCESS = 5; /** * 开启预览失败 */ public static final int PREVIEW_ERROR = 6; /** * 未知错误 */ public static final int UNKNOWN = 7; /** * 不支持的预览尺寸 */ public static final int UNSUPPORTED_PREVIEW_SIZE = 8; /** * 不支持的拍照尺寸 */ public static final int UNSUPPORTED_PICTURE_SIZE = 9; private static final String TAG = Config.TAG; private static final boolean LOG_ENABLE = Config.DEBUG; private final Context mContext; private CameraBuilder mBuilder; private int mCameraId = -1; private android.hardware.Camera mCamera; private android.hardware.Camera.Size mPreviewSize; private android.hardware.Camera.Size mPictureSize; private int mDisplayOrientation; private int mCameraOrientation; private boolean mOpened; private Camera(Context context, CameraBuilder builder) { mContext = context; mBuilder = builder; } /** * 获取相机的方向 * * @return 0 , 90, 180 , 270 */ public int getCameraOrientation() { return mCameraOrientation; } public int getDisplayOrientation() { return mDisplayOrientation; } public CameraBuilder getBuilder() { return mBuilder; } /** * 打开摄像机 * * @return 是否成功 */ @Nullable public synchronized Camera open() { int cameras = android.hardware.Camera.getNumberOfCameras(); if (cameras == 0) { loge("该设备没有相机可用"); handleCameraCallback(NO_CAMERA, "该设备没有相机可用"); return null; } if (mBuilder == null) { loge("没有配置相机"); handleCameraCallback(NOT_CONFIGURED, "没有配置相机"); throw new IllegalStateException("没有配置相机"); } android.hardware.Camera.CameraInfo cameraInfo = new android.hardware.Camera.CameraInfo(); for (int i = 0; i < cameras; i++) { android.hardware.Camera.getCameraInfo(i, cameraInfo); if (cameraInfo.facing == mBuilder.mFacing) mCameraId = i; } if (mCameraId == -1) { loge("设置的相机方向该设备不支持"); handleCameraCallback(UNSUPPORTED_FACING, "设置的相机方向该设备不支持"); return null; } try { if (mCamera != null) close(); mCamera = android.hardware.Camera.open(mCameraId); mOpened = true; } catch (Exception e) { loge(e.toString()); e.printStackTrace(); close(); handleCameraCallback(OPEN_ERROR, e.toString()); return null; } setCameraParameters(); startPreview(); return this; } private void handleCameraCallback(final int code, final String errMsg) { Runnable runnable = new Runnable() { @Override public void run() { if (mBuilder == null) return; for (CameraCallback callback : mBuilder.mCameraCallbacks) { if (TextUtils.isEmpty(errMsg)) { callback.onSuccess(Camera.this); } else { callback.onFailure(code, errMsg); } } } }; if (Looper.getMainLooper().getThread() == Thread.currentThread()) { runnable.run(); } else { new Handler(Looper.getMainLooper()).post(runnable); } } /** * @return 获取预览的尺寸 该方法需要在相机成功预览之后调用才会有正确结果 */ public Size getPreviewSize() { return new Size(mPreviewSize); } /** * @return activity is landscape */ public boolean isLandscape() { WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); if (windowManager != null && windowManager.getDefaultDisplay() != null) { int rotation = windowManager.getDefaultDisplay().getRotation(); LogUtil.logd(TAG, "rotation=" + rotation); return rotation == ROTATION_90 || rotation == ROTATION_270; } return mContext.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; } private void setCameraParameters() { if (mCamera == null) return; android.hardware.Camera.Parameters cameraParameters = getParameters(); if (cameraParameters == null) return; //设置对焦模式 setFocusMode(cameraParameters, mBuilder.mFocusModes); //设置闪光灯模式 setFlashMode(cameraParameters, mBuilder.mFlashModes); //设置场景模式 setSceneMode(cameraParameters, mBuilder.mSceneModes); //色彩效果 setColorEffect(cameraParameters, mBuilder.mColorEffects); //白平衡 setWhiteBalance(cameraParameters, mBuilder.mWhiteBalances); //刷新率 setAntibanding(cameraParameters, mBuilder.mAntibanding); //设置预览帧的像素格式 int previewFormat = getSupportedModelOfInt(cameraParameters.getSupportedPreviewFormats(), mBuilder.mPreviewFormats); if (previewFormat != -1) cameraParameters.setPreviewFormat(previewFormat); //设置图片的像素格式 int pictureFormat = getSupportedModelOfInt(cameraParameters.getSupportedPictureFormats(), mBuilder.mPictureFormats); if (pictureFormat != -1) cameraParameters.setPictureFormat(pictureFormat); //是否是录制模式 cameraParameters.setRecordingHint(mBuilder.mRecordingHint); //设置预览大小 if (mBuilder.mPreviewSizeSelector != null) { mPreviewSize = mBuilder.mPreviewSizeSelector.select(cameraParameters.getSupportedPreviewSizes(), mBuilder.mPreviewSize); } else { mPreviewSize = getOptimalSize("SupportedPreviewSizes", cameraParameters.getSupportedPreviewSizes(), mBuilder.mPreviewSize); } if (mPreviewSize == null) { handleCameraCallback(UNSUPPORTED_PREVIEW_SIZE, "没有找到合适的预览尺寸"); throw new IllegalStateException("没有找到合适的预览尺寸"); } log("requestPreviewSize :" + mBuilder.mPreviewSize.toString() + "\t\t previewSize : " + getPreviewSize().toString()); cameraParameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); //设置拍照的图片尺寸 if (mBuilder.mPictureSize != null) { if (mBuilder.mPictureSizeSelector != null) { mPictureSize = mBuilder.mPictureSizeSelector.select(cameraParameters.getSupportedPreviewSizes(), mBuilder.mPictureSize); } else { mPictureSize = getOptimalSize("SupportedPictureSizes", cameraParameters.getSupportedPictureSizes(), mBuilder.mPictureSize); } if (mPictureSize == null) { handleCameraCallback(UNSUPPORTED_PICTURE_SIZE, "没有找到合适的图片尺寸"); throw new IllegalStateException("没有找到合适的图片尺寸"); } log("requestPictureSize :" + mBuilder.mPictureSize.toString() + "\t\t pictureSize : " + getPictureSize().toString()); cameraParameters.setPictureSize(mPictureSize.width, mPictureSize.height); } //拍照的图片缩放 setZoom(cameraParameters, mBuilder.mZoom); mCamera.setParameters(cameraParameters); log(cameraParameters.flatten().replaceAll(";", ";\t")); } private void setZoom(android.hardware.Camera.Parameters cameraParameters, int zoom) { if (zoom != -1) { int target = clamp(zoom, 0, cameraParameters.getMaxZoom()); if (cameraParameters.isZoomSupported()) cameraParameters.setZoom(target); } } @SuppressWarnings("all") private static int clamp(int x, int min, int max) { if (x > max) { return max; } if (x < min) { return min; } return x; } private void setAntibanding(android.hardware.Camera.Parameters cameraParameters, List<String> antibandings) { String antibanding = getSupportedModelOfString(cameraParameters.getSupportedAntibanding(), antibandings); if (!TextUtils.isEmpty(antibanding)) cameraParameters.setAntibanding(antibanding); } private void setWhiteBalance(android.hardware.Camera.Parameters cameraParameters, List<String> whiteBalances) { String whiteBalance = getSupportedModelOfString(cameraParameters.getSupportedWhiteBalance(), whiteBalances); if (!TextUtils.isEmpty(whiteBalance)) cameraParameters.setWhiteBalance(whiteBalance); } private void setColorEffect(android.hardware.Camera.Parameters cameraParameters, List<String> colorEffects) { String colorEffect = getSupportedModelOfString(cameraParameters.getSupportedColorEffects(), colorEffects); if (!TextUtils.isEmpty(colorEffect)) cameraParameters.setColorEffect(colorEffect); } private void setSceneMode(android.hardware.Camera.Parameters cameraParameters, List<String> sceneModels) { String sceneModel = getSupportedModelOfString(cameraParameters.getSupportedSceneModes(), sceneModels); if (!TextUtils.isEmpty(sceneModel)) cameraParameters.setSceneMode(sceneModel); } private void setFlashMode(android.hardware.Camera.Parameters cameraParameters, List<String> flashModels) { String flashModel = getSupportedModelOfString(cameraParameters.getSupportedFlashModes(), flashModels); if (!TextUtils.isEmpty(flashModel)) cameraParameters.setFlashMode(flashModel); } private void setFocusMode(android.hardware.Camera.Parameters cameraParameters, List<String> focusModels) { String focusMode = getSupportedModelOfString(cameraParameters.getSupportedFocusModes(), focusModels); if (!TextUtils.isEmpty(focusMode)) cameraParameters.setFocusMode(focusMode); } /** * 切换闪光灯状态 */ public synchronized void toggleFlash() { if (mCamera == null) return; try { android.hardware.Camera.Parameters parameters = getParameters(); if (parameters == null) return; if (flashIsOpen()) { //打开状态 - 需要关闭 parameters.setFlashMode(android.hardware.Camera.Parameters.FLASH_MODE_OFF); } else { //关闭状态 - 需要打开 parameters.setFlashMode(android.hardware.Camera.Parameters.FLASH_MODE_TORCH); } mCamera.setParameters(parameters); } catch (Exception e) { e.printStackTrace(); loge("切换闪光灯失败"); } } /** * @return 闪光灯是否开启 */ public boolean flashIsOpen() { android.hardware.Camera.Parameters parameters = getParameters(); return parameters != null && mCamera != null && android.hardware.Camera.Parameters.FLASH_MODE_TORCH.equals(parameters.getFlashMode()); } /** * 切换摄像头朝向 */ public synchronized void toggleFacing() { if (mCamera == null) return; if (getFacing() == android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK) { mBuilder.mFacing = android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT; } else { mBuilder.mFacing = android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK; } open(); } /** * @return 获取当前摄像头的朝向 */ public int getFacing() { if (mCamera == null) return -1; return getCameraInfo(mCameraId).facing; } public Size getPictureSize() { return new Size(mPictureSize); } public void takePicture(android.hardware.Camera.ShutterCallback shutter, android.hardware.Camera.PictureCallback raw, android.hardware.Camera.PictureCallback postview, android.hardware.Camera.PictureCallback jpeg) { if (mCamera == null) return; mCamera.takePicture(shutter, raw, postview, jpeg); } public void takePicture(android.hardware.Camera.ShutterCallback shutter, android.hardware.Camera.PictureCallback raw, android.hardware.Camera.PictureCallback jpeg) { if (mCamera == null) return; takePicture(shutter, raw, null, jpeg); } /** * 设置焦点 * * @param rect 焦点区域 */ public void setFocusAreas(Rect... rect) { if (mCamera == null || rect == null || rect.length == 0) return; final android.hardware.Camera.Parameters parameters = getParameters(); if (parameters == null) return; int maxNumFocusAreas = parameters.getMaxNumFocusAreas(); if (maxNumFocusAreas > 0) { ArrayList<android.hardware.Camera.Area> focusAreas = new ArrayList<>(); for (int i = 0; i < maxNumFocusAreas; i++) { if (i < rect.length) focusAreas.add(new android.hardware.Camera.Area(rect[i], 1000)); } parameters.setFocusAreas(focusAreas); } final String currentFocusMode = parameters.getFocusMode(); if (isSupported(parameters.getSupportedFocusModes(), android.hardware.Camera.Parameters.FOCUS_MODE_AUTO)) { parameters.setFocusMode(android.hardware.Camera.Parameters.FOCUS_MODE_AUTO); mCamera.setParameters(parameters); mCamera.autoFocus(new android.hardware.Camera.AutoFocusCallback() { @Override public void onAutoFocus(boolean b, android.hardware.Camera camera) { //不能用上面的 . 如果对焦的这一段时间参数有更改 , 会丢失 android.hardware.Camera.Parameters cameraParameters = camera.getParameters(); cameraParameters.setFocusMode(currentFocusMode); camera.setParameters(cameraParameters); cancelAutoFocus(); if (mBuilder.mAutoFocusCallback != null) { mBuilder.mAutoFocusCallback.onAutoFocus(b, camera); } } }); } else { mCamera.setParameters(parameters); } } @Nullable private android.hardware.Camera.Parameters getParameters() { try { return mCamera.getParameters(); } catch (Exception e) { e.printStackTrace(); } return null; } private int getSupportedModelOfInt(List<Integer> supportedModel, List<Integer> requestModels) { if (supportedModel != null && !supportedModel.isEmpty() && requestModels != null && !requestModels.isEmpty()) { for (Integer model : requestModels) { if (supportedModel.contains(model)) return model; } } return -1; } @Nullable private String getSupportedModelOfString(List<String> supportedModel, List<String> requestModels) { if (supportedModel != null && !supportedModel.isEmpty() && requestModels != null && !requestModels.isEmpty()) { for (String model : requestModels) { if (isSupported(supportedModel, model)) { return model; } } } return null; } private boolean isSupported(List<String> models, String model) { return !(models == null || models.isEmpty()) && models.contains(model); } /** * 必须成功打开相机之后才有正确的返回结果 * * @return android.hardware.Camera.Parameters */ @Nullable public android.hardware.Camera.Parameters getCameraParameters() { if (mCamera == null) return null; return getParameters(); } /** * 开启相机预览 */ private synchronized void startPreview() { if (mCamera == null) { handleCameraCallback(UNKNOWN, "未知错误"); return; } try { if (mBuilder.mSurfaceTexture != null) { mCamera.setPreviewTexture(mBuilder.mSurfaceTexture); } else if (mBuilder.mSurfaceHolder != null) { mCamera.setPreviewDisplay(mBuilder.mSurfaceHolder); } if (mBuilder.mDisplayOrientation == -1 && mContext != null) { mDisplayOrientation = getCameraDisplayOrientation(getActivityOrientation(mContext)); } else { mDisplayOrientation = mBuilder.mDisplayOrientation; } mCamera.setDisplayOrientation(mDisplayOrientation); mCamera.startPreview(); handleCameraCallback(SUCCESS, null); } catch (Exception e) { loge(e.toString()); e.printStackTrace(); handleCameraCallback(PREVIEW_ERROR, toString()); close(); } } private int getActivityOrientation(Context context) { WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); if (windowManager != null && windowManager.getDefaultDisplay() != null) { return windowManager.getDefaultDisplay().getRotation(); } return 90; } /** * 根据屏幕当前角度计算Camera正确显示所需要的角度 * * @param rotation 屏幕角度 * @return CameraDisplayOrientation * @see android.view.Display#getRotation() */ private int getCameraDisplayOrientation(int rotation) { android.hardware.Camera.CameraInfo info = getCameraInfo(mCameraId); mCameraOrientation = info.orientation; int degrees = 0; switch (rotation) { case Surface.ROTATION_0: degrees = 0; break; case Surface.ROTATION_90: degrees = 90; break; case Surface.ROTATION_180: degrees = 180; break; case Surface.ROTATION_270: degrees = 270; break; } int result; if (info.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT) { result = (info.orientation + degrees) % 360; result = (360 - result) % 360; } else { result = (info.orientation - degrees + 360) % 360; } return result; } @Nullable public android.hardware.Camera.CameraInfo getCameraInfo() { if (mCameraId == -1) return null; android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); android.hardware.Camera.getCameraInfo(mCameraId, info); return info; } @NonNull public android.hardware.Camera.CameraInfo getCameraInfo(int cameraId) { android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); android.hardware.Camera.getCameraInfo(mCameraId, info); return info; } /** * @param tag 日志前綴 * @param supportedPreviewSizes 设备支持的预览尺寸 * @param request 请求的预览尺寸 * @return 在设备支持的尺寸中 , 根据请求的尺寸来寻找一个合适的预览尺寸 , * 如果请求的尺寸是设备支持的 , 那么直接返回该尺寸 ,否则根据指定的宽高来寻找最接近的尺寸 */ private android.hardware.Camera.Size getOptimalSize(String tag, List<android.hardware.Camera.Size> supportedPreviewSizes, Size request) { //排序 Collections.sort(supportedPreviewSizes, new Comparator<android.hardware.Camera.Size>() { // @Override // public int compare(android.hardware.Camera.Size o1, android.hardware.Camera.Size o2) { // return o1.width == o2.width ? o1.height - o2.height : o1.width - o2.width; // } @Override public int compare(android.hardware.Camera.Size pre, android.hardware.Camera.Size after) { return Long.signum((long) pre.width * pre.height - (long) after.width * after.height); } }); if (LOG_ENABLE) { for (android.hardware.Camera.Size size : supportedPreviewSizes) { log(tag + "\t\twidth :" + size.width + "\t height :" + size.height + "\t ratio : " + ((float) size.width / (float) size.height)); } } //如果设备支持请求的尺寸 for (android.hardware.Camera.Size size : supportedPreviewSizes) { if (request.equals(size)) return size; } for (android.hardware.Camera.Size size : supportedPreviewSizes) { if (size.width >= request.width && size.height >= request.height) return size; } //最终还没找到 , 使用最大的 return Collections.max(supportedPreviewSizes, new Comparator<android.hardware.Camera.Size>() { @Override public int compare(android.hardware.Camera.Size pre, android.hardware.Camera.Size after) { return Long.signum((long) pre.width * pre.height - (long) after.width * after.height); } }); } public synchronized void close() { if (mCamera == null) return; try { mOpened = false; mCamera.stopPreview(); mCamera.setPreviewCallbackWithBuffer(null); mCamera.setPreviewCallback(null); mCamera.setErrorCallback(null); mCamera.release(); mCamera = null; } catch (Exception e) { loge(e.getMessage()); e.printStackTrace(); } } public Size getRequestPreviewSize() { return mBuilder.mPreviewSize; } public List<Size> getSupportedPreviewSizes() { ArrayList<Size> sizes = new ArrayList<>(); if (mCamera == null) return sizes; android.hardware.Camera.Parameters cameraParameters = getCameraParameters(); if (cameraParameters == null) return sizes; List<android.hardware.Camera.Size> supportedPreviewSizes = cameraParameters.getSupportedPreviewSizes(); for (android.hardware.Camera.Size previewSize : supportedPreviewSizes) { sizes.add(new Size(previewSize)); } return sizes; } public void setFacing(int facing) { mBuilder.mFacing = facing; open(); } public void setFlashMode(String... flashModes) { if (mCamera == null) return; android.hardware.Camera.Parameters parameters = getParameters(); if (parameters == null) return; setFlashMode(parameters, Arrays.asList(flashModes)); mCamera.setParameters(parameters); } public void setWhiteBalance(String... whiteBalance) { if (mCamera == null) return; android.hardware.Camera.Parameters parameters = getParameters(); if (parameters == null) return; setWhiteBalance(parameters, Arrays.asList(whiteBalance)); mCamera.setParameters(parameters); } public void setMeteringAreas(Rect... rect) { if (mCamera == null || rect == null || rect.length == 0) return; android.hardware.Camera.Parameters parameters = getParameters(); if (parameters != null) { int maxNumMeteringAreas = parameters.getMaxNumMeteringAreas(); if (maxNumMeteringAreas > 0) { ArrayList<android.hardware.Camera.Area> focusAreas = new ArrayList<>(); for (int i = 0; i < maxNumMeteringAreas; i++) { if (i < rect.length) focusAreas.add(new android.hardware.Camera.Area(rect[i], 1000)); } parameters.setMeteringAreas(focusAreas); mCamera.setParameters(parameters); } } else { loge("设置测光区域失败"); } } /** * 设置曝光补偿 * * @param compensation compensation <= maxExposureCompensation && compensation >= minExposureCompensation * @see android.hardware.Camera.Parameters#getMaxExposureCompensation() * @see android.hardware.Camera.Parameters#getMinExposureCompensation() */ public void setExposureCompensation(int compensation) { if (mCamera == null) return; android.hardware.Camera.Parameters parameters = getParameters(); if (parameters == null) return; int maxExposureCompensation = parameters.getMaxExposureCompensation(); int minExposureCompensation = parameters.getMinExposureCompensation(); if (compensation <= maxExposureCompensation && compensation >= minExposureCompensation) { parameters.setExposureCompensation(compensation); mCamera.setParameters(parameters); } } public void setRecordingHint(boolean recording) { if (mCamera == null) return; android.hardware.Camera.Parameters parameters = getParameters(); if (parameters == null) return; parameters.setRecordingHint(recording); mCamera.setParameters(parameters); } public void setAntibanding(String... antibanding) { if (mCamera == null) return; android.hardware.Camera.Parameters parameters = getParameters(); if (parameters == null) return; setAntibanding(parameters, Arrays.asList(antibanding)); mCamera.setParameters(parameters); } public void setFocusMode(String... focusModes) { if (mCamera == null) return; android.hardware.Camera.Parameters parameters = getParameters(); if (parameters == null) return; setFocusMode(parameters, Arrays.asList(focusModes)); mCamera.setParameters(parameters); } public void setColorEffects(String... colorEffects) { if (mCamera == null) return; android.hardware.Camera.Parameters parameters = getParameters(); if (parameters == null) return; setColorEffect(parameters, Arrays.asList(colorEffects)); mCamera.setParameters(parameters); } public void setSceneMode(String... sceneModels) { if (mCamera == null) return; android.hardware.Camera.Parameters parameters = getParameters(); if (parameters == null) return; setSceneMode(parameters, Arrays.asList(sceneModels)); mCamera.setParameters(parameters); } public void setZoom(int zoom) { if (mCamera == null) return; android.hardware.Camera.Parameters parameters = getParameters(); if (parameters == null) return; setZoom(parameters, zoom); mCamera.setParameters(parameters); } public void smoothZoom(int zoom) { if (mCamera == null) return; android.hardware.Camera.Parameters parameters = getParameters(); if (parameters == null) return; int maxZoom = parameters.getMaxZoom(); int target = clamp(zoom, 0, maxZoom); if (parameters.isZoomSupported() && parameters.isSmoothZoomSupported()) { mCamera.startSmoothZoom(target); } } public void setCameraParameters(android.hardware.Camera.Parameters parameters) { if (mCamera == null || parameters == null) return; mCamera.setParameters(parameters); } public List<FpsRange> getSupportedPreviewFpsRange() { ArrayList<FpsRange> fpsRanges = new ArrayList<>(); if (mCamera == null) return fpsRanges; android.hardware.Camera.Parameters parameters = getParameters(); if (parameters == null) return fpsRanges; List<int[]> supportedPreviewFpsRange = parameters.getSupportedPreviewFpsRange(); for (int[] ints : supportedPreviewFpsRange) { fpsRanges.add(new FpsRange(ints)); } return fpsRanges; } public void setPreviewFpsRange(FpsRange fpsRange) { if (mCamera == null) return; android.hardware.Camera.Parameters parameters = getParameters(); if (parameters == null) return; List<FpsRange> supportedPreviewFpsRange = getSupportedPreviewFpsRange(); if (supportedPreviewFpsRange.contains(fpsRange)) { parameters.setPreviewFpsRange(fpsRange.min, fpsRange.max); mCamera.setParameters(parameters); } } public void cancelAutoFocus() { if (mCamera == null) return; mCamera.cancelAutoFocus(); } public boolean isOpen() { return mOpened; } public List<String> getSupportedModes(String... modes) { if (mCamera == null) return null; int cameraId = getCameraId(); if (cameraId == -1) return new ArrayList<>(); ArrayList<String> supportedModes = getMemoryCachedSupportedModes(cameraId, modes); if (supportedModes == null) { //内存没取到 ,从 SharedPreferences 取 supportedModes = getFileCachedSupportedModes(cameraId, modes); if (supportedModes == null) { //文件没取到 , 从Camera取 supportedModes = getSupportedModesFromCamera(modes); } } return supportedModes; } private ArrayList<String> getSupportedModesFromCamera(String... modes) { android.hardware.Camera.Parameters cameraParameters = getCameraParameters(); if (cameraParameters == null) return null; String flatten = cameraParameters.flatten(); int cameraId = getCameraId(); unFlatten(cameraId, flatten); SharedPreferences preferences = mContext.getSharedPreferences(S_CAMERA_SUPPORTED_MODES, Context.MODE_PRIVATE); preferences.edit().putString(S_CAMERA_SUPPORTED_MODES + cameraId, flatten).apply(); return getMemoryCachedSupportedModes(cameraId, modes); } private ArrayList<String> getFileCachedSupportedModes(int cameraId, String... modes) { SharedPreferences preferences = mContext.getSharedPreferences(S_CAMERA_SUPPORTED_MODES, Context.MODE_PRIVATE); String flatten = preferences.getString(S_CAMERA_SUPPORTED_MODES + cameraId, ""); if (!TextUtils.isEmpty(flatten)) { unFlatten(cameraId, flatten); return getMemoryCachedSupportedModes(cameraId, modes); } else { return null; } } private void unFlatten(int cameraId, String flatten) { TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(';'); splitter.setString(flatten); HashMap<String, String> map = new HashMap<>(); for (String kv : splitter) { int pos = kv.indexOf('='); if (pos == -1) continue; String k = kv.substring(0, pos); String v = kv.substring(pos + 1); map.put(k, v); } mSupportedModes.put(cameraId, map); } public ArrayList<String> getMemoryCachedSupportedModes(int cameraId, String... modes) { if (mSupportedModes.size() > 0) { ArrayList<String> supportedModes = new ArrayList<>(); //缓存有数据 HashMap<String, String> map = mSupportedModes.get(cameraId); for (String mode : modes) { String value = map.get(mode); if (!TextUtils.isEmpty(value)) supportedModes.addAll(split(value)); } return supportedModes; } else { return null; } } private ArrayList<String> split(String str) { if (str == null) return null; TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(','); splitter.setString(str); ArrayList<String> substrings = new ArrayList<String>(); for (String s : splitter) { substrings.add(s); } return substrings; } public int getCameraId() { if (mCamera == null) return -1; return mCameraId; } public void setMode(String key, String value) { if (mCamera == null) return; android.hardware.Camera.Parameters parameters = mCamera.getParameters(); if (parameters == null) return; parameters.set(key, value); mCamera.setParameters(parameters); } @SuppressWarnings("unused") public static class CameraBuilder { private final Context mContext; private int mFacing; private Size mPictureSize; private Size mPreviewSize; private List<String> mFlashModes; private SurfaceTexture mSurfaceTexture; private SurfaceHolder mSurfaceHolder; private List<CameraCallback> mCameraCallbacks = new ArrayList<>(); private List<String> mFocusModes; private List<String> mSceneModes; private List<Integer> mPreviewFormats; private List<String> mColorEffects; private List<Integer> mPictureFormats; private int mZoom = -1; private int mDisplayOrientation = -1; private android.hardware.Camera.AutoFocusCallback mAutoFocusCallback; private List<String> mAntibanding; private SizeSelector mPreviewSizeSelector; private SizeSelector mPictureSizeSelector; private boolean mRecordingHint; private List<String> mWhiteBalances; public CameraBuilder(Context context) { mContext = context; } public void release() { mSurfaceHolder = null; mSurfaceTexture = null; if (mCameraCallbacks != null) mCameraCallbacks.clear(); mCameraCallbacks = null; } public CameraBuilder useDefaultConfig() { return setFacing(android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK) .setPreviewSize(new Size(1920, 1080)) .setSceneMode(android.hardware.Camera.Parameters.SCENE_MODE_AUTO) .setFocusMode(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO) .setFlashMode(android.hardware.Camera.Parameters.FLASH_MODE_AUTO) .setPictureSize(new Size(1920, 1080)); } public CameraBuilder setAutoFocusCallback(android.hardware.Camera.AutoFocusCallback autoFocusCallback) { mAutoFocusCallback = autoFocusCallback; return this; } /** * 设置缩放 如果设备支持的话 * 最小值为0 , 最大值为 getMaxZoom() , 如果设置的值大于获取的最大值 , 那么将设置为MaxZoom * * @param zoom 缩放级别 */ public CameraBuilder setZoom(@IntRange(from = 0, to = Integer.MAX_VALUE) int zoom) { mZoom = zoom; return this; } public CameraBuilder setDisplayOrientation(int displayOrientation) { mDisplayOrientation = displayOrientation; return this; } /** * @param size 图片大小 */ public CameraBuilder setPictureSize(@NonNull Size size) { mPictureSize = size; return this; } /** * 是否是录制模式 * * @param recording 录制模式 * @see android.hardware.Camera.Parameters#setRecordingHint(boolean) */ public CameraBuilder setRecordingHint(boolean recording) { mRecordingHint = recording; return this; } /** * @param size 相机预览大小 */ public CameraBuilder setPreviewSize(@NonNull Size size) { mPreviewSize = size; return this; } /** * 摄像头朝向 * * @see android.hardware.Camera.CameraInfo#CAMERA_FACING_BACK * @see android.hardware.Camera.CameraInfo#CAMERA_FACING_FRONT */ public CameraBuilder setFacing(@Facing int facing) { mFacing = facing; return this; } /** * 场景模式 * * @see android.hardware.Camera.Parameters#SCENE_MODE_ACTION * @see android.hardware.Camera.Parameters#SCENE_MODE_AUTO * @see android.hardware.Camera.Parameters#SCENE_MODE_BARCODE * @see android.hardware.Camera.Parameters#SCENE_MODE_BEACH * @see android.hardware.Camera.Parameters#SCENE_MODE_CANDLELIGHT * @see android.hardware.Camera.Parameters#SCENE_MODE_FIREWORKS * @see android.hardware.Camera.Parameters#SCENE_MODE_HDR * @see android.hardware.Camera.Parameters#SCENE_MODE_LANDSCAPE * @see android.hardware.Camera.Parameters#SCENE_MODE_NIGHT * @see android.hardware.Camera.Parameters#SCENE_MODE_NIGHT_PORTRAIT * @see android.hardware.Camera.Parameters#SCENE_MODE_PARTY * @see android.hardware.Camera.Parameters#SCENE_MODE_SNOW * @see android.hardware.Camera.Parameters#SCENE_MODE_PORTRAIT * @see android.hardware.Camera.Parameters#SCENE_MODE_SPORTS * @see android.hardware.Camera.Parameters#SCENE_MODE_THEATRE * @see android.hardware.Camera.Parameters#SCENE_MODE_SUNSET * @see android.hardware.Camera.Parameters#SCENE_MODE_STEADYPHOTO */ public CameraBuilder setSceneMode(@SceneModel String... sceneModes) { mSceneModes = Arrays.asList(sceneModes); return this; } /** * 设置色彩效果 * * @see android.hardware.Camera.Parameters#EFFECT_SEPIA * @see android.hardware.Camera.Parameters#EFFECT_AQUA * @see android.hardware.Camera.Parameters#EFFECT_BLACKBOARD * @see android.hardware.Camera.Parameters#EFFECT_MONO * @see android.hardware.Camera.Parameters#EFFECT_NEGATIVE * @see android.hardware.Camera.Parameters#EFFECT_NONE * @see android.hardware.Camera.Parameters#EFFECT_POSTERIZE * @see android.hardware.Camera.Parameters#EFFECT_SOLARIZE * @see android.hardware.Camera.Parameters#EFFECT_WHITEBOARD */ public CameraBuilder setColorEffects(@ColorEffect String... colorEffects) { mColorEffects = Arrays.asList(colorEffects); return this; } /** * 对焦模式 * * @see android.hardware.Camera.Parameters#FOCUS_MODE_AUTO * @see android.hardware.Camera.Parameters#FOCUS_MODE_CONTINUOUS_VIDEO * @see android.hardware.Camera.Parameters#FOCUS_MODE_CONTINUOUS_PICTURE * @see android.hardware.Camera.Parameters#FOCUS_MODE_EDOF * @see android.hardware.Camera.Parameters#FOCUS_MODE_FIXED * @see android.hardware.Camera.Parameters#FOCUS_MODE_INFINITY * @see android.hardware.Camera.Parameters#FOCUS_MODE_MACRO */ public CameraBuilder setFocusMode(@FocusModel String... focusModes) { mFocusModes = Arrays.asList(focusModes); return this; } /** * 图片格式 * * @see ImageFormat#NV21 * @see ImageFormat#JPEG * @see ImageFormat#RGB_565 */ public CameraBuilder setPictureFormat(@PictureFormat Integer... pictureFormat) { mPictureFormats = Arrays.asList(pictureFormat); return this; } /** * 设置防闪烁参数 ,(由于灯光频率(50HZ或者60HZ)影响的数字相机曝光,进而产生的条纹。) * * @param antibanding 防闪烁值 * @see android.hardware.Camera.Parameters#ANTIBANDING_50HZ * @see android.hardware.Camera.Parameters#ANTIBANDING_60HZ * @see android.hardware.Camera.Parameters#ANTIBANDING_AUTO * @see android.hardware.Camera.Parameters#ANTIBANDING_OFF */ public CameraBuilder setAntibanding(@Antibanding String... antibanding) { mAntibanding = Arrays.asList(antibanding); return this; } /** * 预览帧格式 * * @see ImageFormat#NV21 * @see ImageFormat#YV12 */ public CameraBuilder setPreviewFormat(@PreviewFormat Integer... previewFormat) { mPreviewFormats = Arrays.asList(previewFormat); return this; } /** * 因为某些设备不支持指定的模式 , 所以请设置闪光灯模式优先级列表 * * @see android.hardware.Camera.Parameters#FLASH_MODE_AUTO * @see android.hardware.Camera.Parameters#FLASH_MODE_OFF * @see android.hardware.Camera.Parameters#FLASH_MODE_ON * @see android.hardware.Camera.Parameters#FLASH_MODE_RED_EYE * @see android.hardware.Camera.Parameters#FLASH_MODE_TORCH */ public CameraBuilder setFlashMode(@FlashModel String... flashModes) { mFlashModes = Arrays.asList(flashModes); return this; } /** * 设置比白平衡 * * @param whiteBalance 白平衡 */ public CameraBuilder setWhiteBalance(@WhiteBalance String... whiteBalance) { mWhiteBalances = Arrays.asList(whiteBalance); return this; } /** * 设置使用 SurfaceHolder 预览 */ public CameraBuilder setSurfaceHolder(@NonNull SurfaceHolder surfaceHolder) { mSurfaceHolder = surfaceHolder; return this; } /** * 设置使用 surfaceTexture 预览 */ public CameraBuilder setSurfaceTexture(@NonNull SurfaceTexture surfaceTexture) { mSurfaceTexture = surfaceTexture; return this; } /** * 添加相机预览尺寸选择器 */ public CameraBuilder setPreviewSizeSelector(SizeSelector sizeSelector) { mPreviewSizeSelector = sizeSelector; return this; } /** * 添加相机拍照尺寸选择器 */ public CameraBuilder setPictureSizeSelector(SizeSelector sizeSelector) { mPictureSizeSelector = sizeSelector; return this; } /** * 添加相机预览的回调 */ public CameraBuilder addPreviewCallback(@NonNull CameraCallback callback) { mCameraCallbacks.add(callback); return this; } /** * 构建相机参数 * * @return Camera */ public Camera build() { return new Camera(this.mContext, this); } /** * 构建相机参数 * * @return Camera */ public Camera build(CameraBuilder builder) { mFacing = builder.mFacing; mPictureSize = builder.mPictureSize; mPreviewSize = builder.mPreviewSize; mFlashModes = builder.mFlashModes; mSurfaceTexture = builder.mSurfaceTexture; mSurfaceHolder = builder.mSurfaceHolder; mCameraCallbacks = new ArrayList<>(); mCameraCallbacks.addAll(builder.mCameraCallbacks); mFocusModes = builder.mFocusModes; mSceneModes = builder.mSceneModes; mPreviewFormats = builder.mPreviewFormats; mColorEffects = builder.mColorEffects; mWhiteBalances = builder.mWhiteBalances; mPictureFormats = builder.mPictureFormats; mZoom = builder.mZoom; mDisplayOrientation = builder.mDisplayOrientation; mAutoFocusCallback = builder.mAutoFocusCallback; mAntibanding = builder.mAntibanding; return new Camera(mContext, this); } } public interface SizeSelector { /** * 选择合适的尺寸 * * @param supportedSizes 支持的尺寸列表 * @param requestSize 期望的尺寸 * @return 最终的尺寸 */ android.hardware.Camera.Size select(List<android.hardware.Camera.Size> supportedSizes, Size requestSize); } public interface CameraCallback { /** * 打开相机成功 * 如果使用的是 SurfaceView预览 , 可以在这个回调里根据camera.getPreviewSize() 重新调整SurfaceView的大小比例 , 避免预览变形 */ void onSuccess(Camera camera); /** * 相机预览失败回调 * * @see Camera#NO_CAMERA * @see Camera#NOT_CONFIGURED * @see Camera#UNSUPPORTED_FACING * @see Camera#OPEN_ERROR * @see Camera#SUCCESS * @see Camera#PREVIEW_ERROR * @see Camera#UNKNOWN * @see Camera#UNSUPPORTED_PREVIEW_SIZE * @see Camera#UNSUPPORTED_PICTURE_SIZE */ void onFailure(int code, String msg); } public void log(String msg) { if (LOG_ENABLE) Log.d(TAG, msg); } public void loge(String msg) { if (LOG_ENABLE) Log.e(TAG, msg); } }