package org.webrtc; import android.annotation.TargetApi; import android.content.Context; import android.graphics.Rect; import android.graphics.SurfaceTexture; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraManager; import android.hardware.camera2.params.StreamConfigurationMap; import android.os.Build; import android.os.SystemClock; import android.util.AndroidException; import android.util.Range; import android.util.Size; import androidx.annotation.Nullable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.webrtc.CameraEnumerationAndroid; import org.webrtc.CameraVideoCapturer; @TargetApi(21) public class Camera2Enumerator implements CameraEnumerator { private static final double NANO_SECONDS_PER_SECOND = 1.0E9d; private static final String TAG = "Camera2Enumerator"; private static final Map> cachedSupportedFormats = new HashMap(); @Nullable public final CameraManager cameraManager; public final Context context; public Camera2Enumerator(Context context) { this.context = context; this.cameraManager = (CameraManager) context.getSystemService("camera"); } public static List convertFramerates(Range[] rangeArr, int i) { ArrayList arrayList = new ArrayList(); for (Range range : rangeArr) { arrayList.add(new CameraEnumerationAndroid.CaptureFormat.FramerateRange(range.getLower().intValue() * i, range.getUpper().intValue() * i)); } return arrayList; } private static List convertSizes(@Nullable Size[] sizeArr) { ArrayList arrayList = new ArrayList(); if (sizeArr != null) { for (Size size : sizeArr) { arrayList.add(new Size(size.getWidth(), size.getHeight())); } } return arrayList; } @Nullable private CameraCharacteristics getCameraCharacteristics(String str) { try { return this.cameraManager.getCameraCharacteristics(str); } catch (AndroidException e) { Logging.e("Camera2Enumerator", "Camera access exception: " + e); return null; } } public static int getFpsUnitFactor(Range[] rangeArr) { return (rangeArr.length != 0 && rangeArr[0].getUpper().intValue() >= 1000) ? 1 : 1000; } @Nullable public static List getSupportedFormats(Context context, String str) { return getSupportedFormats((CameraManager) context.getSystemService("camera"), str); } @Nullable public static List getSupportedFormats(CameraManager cameraManager, String str) { long j; Map> map = cachedSupportedFormats; synchronized (map) { if (map.containsKey(str)) { return map.get(str); } Logging.d("Camera2Enumerator", "Get supported formats for camera index " + str + "."); long elapsedRealtime = SystemClock.elapsedRealtime(); try { CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(str); StreamConfigurationMap streamConfigurationMap = (StreamConfigurationMap) cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); Range[] rangeArr = (Range[]) cameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); List convertFramerates = convertFramerates(rangeArr, getFpsUnitFactor(rangeArr)); List supportedSizes = getSupportedSizes(cameraCharacteristics); int i = 0; for (CameraEnumerationAndroid.CaptureFormat.FramerateRange framerateRange : convertFramerates) { i = Math.max(i, framerateRange.max); } ArrayList arrayList = new ArrayList(); for (Size size : supportedSizes) { try { j = streamConfigurationMap.getOutputMinFrameDuration(SurfaceTexture.class, new Size(size.width, size.height)); } catch (Exception unused) { j = 0; } int round = j == 0 ? i : ((int) Math.round(1.0E9d / ((double) j))) * 1000; arrayList.add(new CameraEnumerationAndroid.CaptureFormat(size.width, size.height, 0, round)); Logging.d("Camera2Enumerator", "Format: " + size.width + "x" + size.height + "@" + round); } cachedSupportedFormats.put(str, arrayList); long elapsedRealtime2 = SystemClock.elapsedRealtime(); Logging.d("Camera2Enumerator", "Get supported formats for camera index " + str + " done. Time spent: " + (elapsedRealtime2 - elapsedRealtime) + " ms."); return arrayList; } catch (Exception e) { Logging.e("Camera2Enumerator", "getCameraCharacteristics(): " + e); return new ArrayList(); } } } public static List getSupportedSizes(CameraCharacteristics cameraCharacteristics) { int intValue = ((Integer) cameraCharacteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL)).intValue(); List convertSizes = convertSizes(((StreamConfigurationMap) cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)).getOutputSizes(SurfaceTexture.class)); if (Build.VERSION.SDK_INT >= 22 || intValue != 2) { return convertSizes; } Rect rect = (Rect) cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); ArrayList arrayList = new ArrayList(); for (Size size : convertSizes) { if (rect.width() * size.height == rect.height() * size.width) { arrayList.add(size); } } return arrayList; } public static boolean isSupported(Context context) { CameraManager cameraManager = (CameraManager) context.getSystemService("camera"); try { for (String str : cameraManager.getCameraIdList()) { CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(str); if (((Integer) cameraCharacteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL)).intValue() == 2 || getSupportedSizes(cameraCharacteristics).isEmpty()) { return false; } } return true; } catch (AndroidException e) { Logging.e("Camera2Enumerator", "Camera access exception: " + e); return false; } catch (Throwable th) { Logging.e("Camera2Enumerator", "Uncaught camera exception: " + th); return false; } } @Override // org.webrtc.CameraEnumerator public CameraVideoCapturer createCapturer(String str, CameraVideoCapturer.CameraEventsHandler cameraEventsHandler) { return new Camera2Capturer(this.context, str, cameraEventsHandler); } @Override // org.webrtc.CameraEnumerator public String[] getDeviceNames() { try { return this.cameraManager.getCameraIdList(); } catch (AndroidException e) { Logging.e("Camera2Enumerator", "Camera access exception: " + e); return new String[0]; } } @Override // org.webrtc.CameraEnumerator @Nullable public List getSupportedFormats(String str) { return getSupportedFormats(this.context, str); } @Override // org.webrtc.CameraEnumerator public boolean isBackFacing(String str) { CameraCharacteristics cameraCharacteristics = getCameraCharacteristics(str); return cameraCharacteristics != null && ((Integer) cameraCharacteristics.get(CameraCharacteristics.LENS_FACING)).intValue() == 1; } @Override // org.webrtc.CameraEnumerator public boolean isFrontFacing(String str) { CameraCharacteristics cameraCharacteristics = getCameraCharacteristics(str); return cameraCharacteristics != null && ((Integer) cameraCharacteristics.get(CameraCharacteristics.LENS_FACING)).intValue() == 0; } }