Chromium Code Reviews| Index: webrtc/api/java/android/org/webrtc/Camera2Enumerator.java |
| diff --git a/webrtc/api/java/android/org/webrtc/Camera2Enumerator.java b/webrtc/api/java/android/org/webrtc/Camera2Enumerator.java |
| index 8c342c5c25b51716dd6f1149945330bb22535d9e..1342538ba6c91397b2b4829b2a2454ececbea4d3 100644 |
| --- a/webrtc/api/java/android/org/webrtc/Camera2Enumerator.java |
| +++ b/webrtc/api/java/android/org/webrtc/Camera2Enumerator.java |
| @@ -14,13 +14,15 @@ import android.annotation.TargetApi; |
| import android.content.Context; |
| import android.graphics.ImageFormat; |
| +import android.graphics.SurfaceTexture; |
| +import android.hardware.camera2.CameraAccessException; |
| import android.hardware.camera2.CameraCharacteristics; |
| import android.hardware.camera2.CameraManager; |
| +import android.hardware.camera2.CameraMetadata; |
| import android.hardware.camera2.params.StreamConfigurationMap; |
| import android.os.Build; |
| import android.os.SystemClock; |
| import android.util.Range; |
| -import android.util.Size; |
| import org.webrtc.CameraEnumerationAndroid.CaptureFormat; |
| import org.webrtc.Logging; |
| @@ -31,7 +33,7 @@ import java.util.List; |
| import java.util.Map; |
| @TargetApi(21) |
| -public class Camera2Enumerator { |
| +public class Camera2Enumerator implements CameraEnumerator { |
| private final static String TAG = "Camera2Enumerator"; |
| private final static double NANO_SECONDS_PER_SECOND = 1.0e9; |
| @@ -40,21 +42,100 @@ public class Camera2Enumerator { |
| private static final Map<String, List<CaptureFormat>> cachedSupportedFormats = |
| new HashMap<String, List<CaptureFormat>>(); |
| + final Context context; |
| + final CameraManager cameraManager; |
| + |
| + public Camera2Enumerator(Context context) { |
| + this.context = context; |
| + this.cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); |
| + } |
| + |
| + public String[] getDeviceNames() { |
| + try { |
| + return cameraManager.getCameraIdList(); |
| + } catch (CameraAccessException e) { |
| + Logging.e(TAG, "Camera access exception: " + e); |
| + return new String[] {}; |
| + } |
| + } |
| + |
| + public boolean isFrontFacing(String deviceName) { |
| + CameraCharacteristics characteristics |
| + = getCameraCharacteristics(deviceName); |
| + |
| + return characteristics != null |
| + && characteristics.get(CameraCharacteristics.LENS_FACING) |
| + == CameraMetadata.LENS_FACING_FRONT; |
| + } |
| + |
| + public boolean isBackFacing(String deviceName) { |
| + CameraCharacteristics characteristics |
| + = getCameraCharacteristics(deviceName); |
| + |
| + return characteristics != null |
| + && characteristics.get(CameraCharacteristics.LENS_FACING) |
| + == CameraMetadata.LENS_FACING_BACK; |
| + } |
| + |
| + public CameraVideoCapturer createCapturer(String deviceName, |
| + CameraVideoCapturer.CameraEventsHandler eventsHandler) { |
| + return new Camera2Capturer(context, deviceName, eventsHandler); |
| + } |
| + |
| + private CameraCharacteristics getCameraCharacteristics(String deviceName) { |
| + try { |
| + return cameraManager.getCameraCharacteristics(deviceName); |
| + } catch (CameraAccessException e) { |
| + Logging.e(TAG, "Camera access exception: " + e); |
| + return null; |
| + } |
| + } |
| + |
| public static boolean isSupported() { |
| return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; |
| } |
| - public static List<CaptureFormat> getSupportedFormats(Context context, String cameraId) { |
| + static List<CaptureFormat.FramerateRange> getSupportedFramerateRanges( |
| + CameraCharacteristics cameraCharacteristics) { |
| + final Range<Integer>[] fpsRanges = |
| + cameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); |
| + |
| + if (fpsRanges == null) { |
| + return new ArrayList<CaptureFormat.FramerateRange>(); |
| + } |
| + |
| + int maxFps = 0; |
| + for (Range<Integer> fpsRange : fpsRanges) { |
| + maxFps = Math.max(maxFps, fpsRange.getUpper()); |
| + } |
| + int unitFactor = maxFps < 1000 ? 1000 : 1; |
| + return convertFramerates(fpsRanges, unitFactor); |
| + } |
| + |
| + static List<Size> getSupportedSizes( |
| + CameraCharacteristics cameraCharacteristics) { |
| + final StreamConfigurationMap streamMap = |
| + cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); |
| + final android.util.Size[] sizes = streamMap.getOutputSizes(SurfaceTexture.class); |
| + if (sizes == null) { |
| + Logging.e(TAG, "No supported camera output sizes."); |
| + return new ArrayList<Size>(); |
| + } |
| + return convertSizes(sizes); |
| + } |
| + |
| + static List<CaptureFormat> getSupportedFormats(Context context, String cameraId) { |
| return getSupportedFormats( |
| (CameraManager) context.getSystemService(Context.CAMERA_SERVICE), cameraId); |
| } |
| - public static List<CaptureFormat> getSupportedFormats( |
| + static List<CaptureFormat> getSupportedFormats( |
| CameraManager cameraManager, String cameraId) { |
| synchronized (cachedSupportedFormats) { |
| if (cachedSupportedFormats.containsKey(cameraId)) { |
| return cachedSupportedFormats.get(cameraId); |
| } |
| + |
| Logging.d(TAG, "Get supported formats for camera index " + cameraId + "."); |
| final long startTimeMs = SystemClock.elapsedRealtime(); |
| @@ -66,35 +147,37 @@ public class Camera2Enumerator { |
| return new ArrayList<CaptureFormat>(); |
| } |
| - // Calculate default max fps from auto-exposure ranges in case getOutputMinFrameDuration() is |
| - // not supported. |
| - final Range<Integer>[] fpsRanges = |
| - cameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); |
| - int defaultMaxFps = 0; |
| - for (Range<Integer> fpsRange : fpsRanges) { |
| - defaultMaxFps = Math.max(defaultMaxFps, fpsRange.getUpper()); |
| - } |
| - |
| final StreamConfigurationMap streamMap = |
| cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); |
| - final Size[] sizes = streamMap.getOutputSizes(ImageFormat.YUV_420_888); |
| - if (sizes == null) { |
| - throw new RuntimeException("ImageFormat.YUV_420_888 not supported."); |
| + |
| + List<CaptureFormat.FramerateRange> framerateRanges = getSupportedFramerateRanges( |
| + cameraCharacteristics); |
| + List<Size> sizes = getSupportedSizes(cameraCharacteristics); |
| + |
| + int defaultMaxFps = 0; |
| + for (CaptureFormat.FramerateRange framerateRange : framerateRanges) { |
| + defaultMaxFps = Math.max(defaultMaxFps, framerateRange.max); |
| + } |
| + if (defaultMaxFps < 1000) { |
|
magjed_webrtc
2016/06/27 10:33:24
This check should not be needed for CaptureFormat.
sakal
2016/06/27 12:08:28
You're right.
|
| + defaultMaxFps *= 1000; |
| } |
| final List<CaptureFormat> formatList = new ArrayList<CaptureFormat>(); |
| for (Size size : sizes) { |
| long minFrameDurationNs = 0; |
| try { |
| - minFrameDurationNs = streamMap.getOutputMinFrameDuration(ImageFormat.YUV_420_888, size); |
| + minFrameDurationNs = streamMap.getOutputMinFrameDuration(SurfaceTexture.class, |
| + new android.util.Size(size.width, size.height)); |
| } catch (Exception e) { |
| // getOutputMinFrameDuration() is not supported on all devices. Ignore silently. |
| } |
| final int maxFps = (minFrameDurationNs == 0) |
| - ? defaultMaxFps |
| - : (int) Math.round(NANO_SECONDS_PER_SECOND / minFrameDurationNs); |
| - formatList.add(new CaptureFormat(size.getWidth(), size.getHeight(), 0, maxFps * 1000)); |
| + ? defaultMaxFps |
| + : (int) Math.round(NANO_SECONDS_PER_SECOND / minFrameDurationNs) * 1000; |
| + formatList.add(new CaptureFormat(size.width, size.height, 0, maxFps)); |
| + Logging.d(TAG, "Format: " + size.width + "x" + size.height + "@" + maxFps); |
| } |
| + |
| cachedSupportedFormats.put(cameraId, formatList); |
| final long endTimeMs = SystemClock.elapsedRealtime(); |
| Logging.d(TAG, "Get supported formats for camera index " + cameraId + " done." |
| @@ -102,4 +185,25 @@ public class Camera2Enumerator { |
| return formatList; |
| } |
| } |
| + |
| + // Convert from android.util.Size to Size. |
| + public static List<Size> convertSizes(android.util.Size[] cameraSizes) { |
|
magjed_webrtc
2016/06/27 10:33:24
Can this be a private method instead?
sakal
2016/06/27 12:08:28
I changed this. I reduced visibility in Camera1Enu
|
| + final List<Size> sizes = new ArrayList<Size>(); |
| + for (android.util.Size size : cameraSizes) { |
| + sizes.add(new Size(size.getWidth(), size.getHeight())); |
| + } |
| + return sizes; |
| + } |
| + |
| + // Convert from android.util.Range<Integer> to CaptureFormat.FramerateRange. |
| + public static List<CaptureFormat.FramerateRange> convertFramerates( |
|
magjed_webrtc
2016/06/27 10:33:24
ditto, private?
|
| + Range<Integer>[] arrayRanges, int unitFactor) { |
| + final List<CaptureFormat.FramerateRange> ranges = new ArrayList<CaptureFormat.FramerateRange>(); |
| + for (Range<Integer> range : arrayRanges) { |
| + ranges.add(new CaptureFormat.FramerateRange( |
| + range.getLower() * unitFactor, |
| + range.getUpper() * unitFactor)); |
| + } |
| + return ranges; |
| + } |
| } |