| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. | |
| 3 * | |
| 4 * Use of this source code is governed by a BSD-style license | |
| 5 * that can be found in the LICENSE file in the root of the source | |
| 6 * tree. An additional intellectual property rights grant can be found | |
| 7 * in the file PATENTS. All contributing project authors may | |
| 8 * be found in the AUTHORS file in the root of the source tree. | |
| 9 */ | |
| 10 | |
| 11 package org.webrtc; | |
| 12 | |
| 13 import static java.lang.Math.abs; | |
| 14 | |
| 15 import android.graphics.ImageFormat; | |
| 16 | |
| 17 import java.util.Collections; | |
| 18 import java.util.Comparator; | |
| 19 import java.util.List; | |
| 20 | |
| 21 @SuppressWarnings("deprecation") | |
| 22 public class CameraEnumerationAndroid { | |
| 23 private final static String TAG = "CameraEnumerationAndroid"; | |
| 24 | |
| 25 public static class CaptureFormat { | |
| 26 // Class to represent a framerate range. The framerate varies because of lig
htning conditions. | |
| 27 // The values are multiplied by 1000, so 1000 represents one frame per secon
d. | |
| 28 public static class FramerateRange { | |
| 29 public int min; | |
| 30 public int max; | |
| 31 | |
| 32 public FramerateRange(int min, int max) { | |
| 33 this.min = min; | |
| 34 this.max = max; | |
| 35 } | |
| 36 | |
| 37 @Override | |
| 38 public String toString() { | |
| 39 return "[" + (min / 1000.0f) + ":" + (max / 1000.0f) + "]"; | |
| 40 } | |
| 41 | |
| 42 @Override | |
| 43 public boolean equals(Object other) { | |
| 44 if (!(other instanceof FramerateRange)) { | |
| 45 return false; | |
| 46 } | |
| 47 final FramerateRange otherFramerate = (FramerateRange) other; | |
| 48 return min == otherFramerate.min && max == otherFramerate.max; | |
| 49 } | |
| 50 | |
| 51 @Override | |
| 52 public int hashCode() { | |
| 53 // Use prime close to 2^16 to avoid collisions for normal values less th
an 2^16. | |
| 54 return 1 + 65537 * min + max; | |
| 55 } | |
| 56 } | |
| 57 | |
| 58 public final int width; | |
| 59 public final int height; | |
| 60 public final FramerateRange framerate; | |
| 61 | |
| 62 // TODO(hbos): If VideoCapturer.startCapture is updated to support other ima
ge formats then this | |
| 63 // needs to be updated and VideoCapturer.getSupportedFormats need to return
CaptureFormats of | |
| 64 // all imageFormats. | |
| 65 public final int imageFormat = ImageFormat.NV21; | |
| 66 | |
| 67 public CaptureFormat(int width, int height, int minFramerate, int maxFramera
te) { | |
| 68 this.width = width; | |
| 69 this.height = height; | |
| 70 this.framerate = new FramerateRange(minFramerate, maxFramerate); | |
| 71 } | |
| 72 | |
| 73 public CaptureFormat(int width, int height, FramerateRange framerate) { | |
| 74 this.width = width; | |
| 75 this.height = height; | |
| 76 this.framerate = framerate; | |
| 77 } | |
| 78 | |
| 79 // Calculates the frame size of this capture format. | |
| 80 public int frameSize() { | |
| 81 return frameSize(width, height, imageFormat); | |
| 82 } | |
| 83 | |
| 84 // Calculates the frame size of the specified image format. Currently only | |
| 85 // supporting ImageFormat.NV21. | |
| 86 // The size is width * height * number of bytes per pixel. | |
| 87 // http://developer.android.com/reference/android/hardware/Camera.html#addCa
llbackBuffer(byte[]) | |
| 88 public static int frameSize(int width, int height, int imageFormat) { | |
| 89 if (imageFormat != ImageFormat.NV21) { | |
| 90 throw new UnsupportedOperationException("Don't know how to calculate " | |
| 91 + "the frame size of non-NV21 image formats."); | |
| 92 } | |
| 93 return (width * height * ImageFormat.getBitsPerPixel(imageFormat)) / 8; | |
| 94 } | |
| 95 | |
| 96 @Override | |
| 97 public String toString() { | |
| 98 return width + "x" + height + "@" + framerate; | |
| 99 } | |
| 100 | |
| 101 @Override | |
| 102 public boolean equals(Object other) { | |
| 103 if (!(other instanceof CaptureFormat)) { | |
| 104 return false; | |
| 105 } | |
| 106 final CaptureFormat otherFormat = (CaptureFormat) other; | |
| 107 return width == otherFormat.width && height == otherFormat.height | |
| 108 && framerate.equals(otherFormat.framerate); | |
| 109 } | |
| 110 | |
| 111 @Override | |
| 112 public int hashCode() { | |
| 113 return 1 + (width * 65497 + height) * 251 + framerate.hashCode(); | |
| 114 } | |
| 115 } | |
| 116 | |
| 117 /** | |
| 118 * @deprecated | |
| 119 * Please use Camera1Enumerator.getDeviceNames() instead. | |
| 120 */ | |
| 121 @Deprecated | |
| 122 public static String[] getDeviceNames() { | |
| 123 return new Camera1Enumerator().getDeviceNames(); | |
| 124 } | |
| 125 | |
| 126 | |
| 127 /** | |
| 128 * @deprecated | |
| 129 * Please use Camera1Enumerator.getDeviceNames().length instead. | |
| 130 */ | |
| 131 @Deprecated | |
| 132 public static int getDeviceCount() { | |
| 133 return new Camera1Enumerator().getDeviceNames().length; | |
| 134 } | |
| 135 | |
| 136 /** | |
| 137 * @deprecated | |
| 138 * Please use Camera1Enumerator.getDeviceNames().get(index) instead. | |
| 139 */ | |
| 140 @Deprecated | |
| 141 public static String getDeviceName(int index) { | |
| 142 return new Camera1Enumerator().getDeviceName(index); | |
| 143 } | |
| 144 | |
| 145 /** | |
| 146 * @deprecated | |
| 147 * Please use Camera1Enumerator.isFrontFacing(String deviceName) instead. | |
| 148 */ | |
| 149 @Deprecated | |
| 150 public static String getNameOfFrontFacingDevice() { | |
| 151 return getNameOfDevice(android.hardware.Camera.CameraInfo.CAMERA_FACING_FRON
T); | |
| 152 } | |
| 153 | |
| 154 /** | |
| 155 * @deprecated | |
| 156 * Please use Camera1Enumerator.isBackFacing(String deviceName) instead. | |
| 157 */ | |
| 158 @Deprecated | |
| 159 public static String getNameOfBackFacingDevice() { | |
| 160 return getNameOfDevice(android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK
); | |
| 161 } | |
| 162 | |
| 163 // Helper class for finding the closest supported format for the two functions
below. It creates a | |
| 164 // comparator based on the difference to some requested parameters, where the
element with the | |
| 165 // minimum difference is the element that is closest to the requested paramete
rs. | |
| 166 private static abstract class ClosestComparator<T> implements Comparator<T> { | |
| 167 // Difference between supported and requested parameter. | |
| 168 abstract int diff(T supportedParameter); | |
| 169 | |
| 170 @Override | |
| 171 public int compare(T t1, T t2) { | |
| 172 return diff(t1) - diff(t2); | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 // Prefer a fps range with an upper bound close to |framerate|. Also prefer a
fps range with a low | |
| 177 // lower bound, to allow the framerate to fluctuate based on lightning conditi
ons. | |
| 178 public static CaptureFormat.FramerateRange getClosestSupportedFramerateRange( | |
| 179 List<CaptureFormat.FramerateRange> supportedFramerates, final int requeste
dFps) { | |
| 180 return Collections.min(supportedFramerates, | |
| 181 new ClosestComparator<CaptureFormat.FramerateRange>() { | |
| 182 // Progressive penalty if the upper bound is further away than |MAX_FP
S_DIFF_THRESHOLD| | |
| 183 // from requested. | |
| 184 private static final int MAX_FPS_DIFF_THRESHOLD = 5000; | |
| 185 private static final int MAX_FPS_LOW_DIFF_WEIGHT = 1; | |
| 186 private static final int MAX_FPS_HIGH_DIFF_WEIGHT = 3; | |
| 187 | |
| 188 // Progressive penalty if the lower bound is bigger than |MIN_FPS_THRE
SHOLD|. | |
| 189 private static final int MIN_FPS_THRESHOLD = 8000; | |
| 190 private static final int MIN_FPS_LOW_VALUE_WEIGHT = 1; | |
| 191 private static final int MIN_FPS_HIGH_VALUE_WEIGHT = 4; | |
| 192 | |
| 193 // Use one weight for small |value| less than |threshold|, and another
weight above. | |
| 194 private int progressivePenalty(int value, int threshold, int lowWeight
, int highWeight) { | |
| 195 return (value < threshold) | |
| 196 ? value * lowWeight | |
| 197 : threshold * lowWeight + (value - threshold) * highWeight; | |
| 198 } | |
| 199 | |
| 200 @Override | |
| 201 int diff(CaptureFormat.FramerateRange range) { | |
| 202 final int minFpsError = progressivePenalty(range.min, | |
| 203 MIN_FPS_THRESHOLD, MIN_FPS_LOW_VALUE_WEIGHT, MIN_FPS_HIGH_VALUE_
WEIGHT); | |
| 204 final int maxFpsError = progressivePenalty(Math.abs(requestedFps * 1
000 - range.max), | |
| 205 MAX_FPS_DIFF_THRESHOLD, MAX_FPS_LOW_DIFF_WEIGHT, MAX_FPS_HIGH_DI
FF_WEIGHT); | |
| 206 return minFpsError + maxFpsError; | |
| 207 } | |
| 208 }); | |
| 209 } | |
| 210 | |
| 211 public static Size getClosestSupportedSize( | |
| 212 List<Size> supportedSizes, final int requestedWidth, | |
| 213 final int requestedHeight) { | |
| 214 return Collections.min(supportedSizes, | |
| 215 new ClosestComparator<Size>() { | |
| 216 @Override | |
| 217 int diff(Size size) { | |
| 218 return abs(requestedWidth - size.width) + abs(requestedHeight - size
.height); | |
| 219 } | |
| 220 }); | |
| 221 } | |
| 222 | |
| 223 private static String getNameOfDevice(int facing) { | |
| 224 final android.hardware.Camera.CameraInfo info = new android.hardware.Camera.
CameraInfo(); | |
| 225 for (int i = 0; i < android.hardware.Camera.getNumberOfCameras(); ++i) { | |
| 226 try { | |
| 227 android.hardware.Camera.getCameraInfo(i, info); | |
| 228 if (info.facing == facing) { | |
| 229 return getDeviceName(i); | |
| 230 } | |
| 231 } catch (Exception e) { | |
| 232 Logging.e(TAG, "getCameraInfo() failed on index " + i, e); | |
| 233 } | |
| 234 } | |
| 235 return null; | |
| 236 } | |
| 237 } | |
| OLD | NEW |