1 /* 2 * Copyright 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.hardware.camera2.utils; 18 19 import static android.system.OsConstants.EINVAL; 20 21 import static com.android.internal.util.Preconditions.checkNotNull; 22 23 import android.compat.annotation.UnsupportedAppUsage; 24 import android.graphics.ImageFormat; 25 import android.graphics.PixelFormat; 26 import android.hardware.HardwareBuffer; 27 import android.hardware.camera2.params.StreamConfigurationMap; 28 import android.util.Range; 29 import android.util.Size; 30 import android.view.Surface; 31 32 import java.util.Arrays; 33 import java.util.Collection; 34 import java.util.Iterator; 35 import java.util.List; 36 37 /** 38 * Various Surface utilities. 39 */ 40 public class SurfaceUtils { 41 42 // Usage flags not yet included in HardwareBuffer 43 private static final int USAGE_RENDERSCRIPT = 0x00100000; 44 private static final int USAGE_HW_COMPOSER = 0x00000800; 45 46 // Image formats not yet included in PixelFormat 47 private static final int BGRA_8888 = 0x5; 48 49 private static final int BAD_VALUE = -EINVAL; 50 51 /** 52 * Check if a surface is for preview consumer based on consumer end point Gralloc usage flags. 53 * 54 * @param surface The surface to be checked. 55 * @return true if the surface is for preview consumer, false otherwise. 56 */ isSurfaceForPreview(Surface surface)57 public static boolean isSurfaceForPreview(Surface surface) { 58 checkNotNull(surface); 59 long usageFlags = nativeDetectSurfaceUsageFlags(surface); 60 long disallowedFlags = HardwareBuffer.USAGE_VIDEO_ENCODE | USAGE_RENDERSCRIPT 61 | HardwareBuffer.USAGE_CPU_READ_OFTEN; 62 long allowedFlags = HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE | USAGE_HW_COMPOSER 63 | HardwareBuffer.USAGE_GPU_COLOR_OUTPUT; 64 boolean previewConsumer = ((usageFlags & disallowedFlags) == 0 65 && (usageFlags & allowedFlags) != 0); 66 int surfaceFormat = getSurfaceFormat(surface); 67 68 return previewConsumer; 69 } 70 71 /** 72 * Check if the surface is for hardware video encoder consumer based on consumer end point 73 * Gralloc usage flags. 74 * 75 * @param surface The surface to be checked. 76 * @return true if the surface is for hardware video encoder consumer, false otherwise. 77 */ isSurfaceForHwVideoEncoder(Surface surface)78 public static boolean isSurfaceForHwVideoEncoder(Surface surface) { 79 checkNotNull(surface); 80 long usageFlags = nativeDetectSurfaceUsageFlags(surface); 81 long disallowedFlags = USAGE_HW_COMPOSER 82 | USAGE_RENDERSCRIPT | HardwareBuffer.USAGE_CPU_READ_OFTEN; 83 long allowedFlags = HardwareBuffer.USAGE_VIDEO_ENCODE; 84 boolean videoEncoderConsumer = ((usageFlags & disallowedFlags) == 0 85 && (usageFlags & allowedFlags) != 0); 86 87 int surfaceFormat = getSurfaceFormat(surface); 88 89 return videoEncoderConsumer; 90 } 91 92 /** 93 * Get the native object id of a surface. 94 * 95 * @param surface The surface to be checked. 96 * @return the native object id of the surface, 0 if surface is not backed by a native object. 97 */ getSurfaceId(Surface surface)98 public static long getSurfaceId(Surface surface) { 99 checkNotNull(surface); 100 try { 101 return nativeGetSurfaceId(surface); 102 } catch (IllegalArgumentException e) { 103 return 0; 104 } 105 } 106 107 /** 108 * Get the surface usage bits. 109 * 110 * @param surface The surface to be queried for usage. 111 * @return the native object id of the surface, 0 if surface is not backed by a native object. 112 */ getSurfaceUsage(Surface surface)113 public static long getSurfaceUsage(Surface surface) { 114 checkNotNull(surface); 115 try { 116 return nativeDetectSurfaceUsageFlags(surface); 117 } catch (IllegalArgumentException e) { 118 return 0; 119 } 120 } 121 /** 122 * Get the Surface size. 123 * 124 * @param surface The surface to be queried for size. 125 * @return Size of the surface. 126 * 127 * @throws IllegalArgumentException if the surface is already abandoned. 128 */ 129 @UnsupportedAppUsage getSurfaceSize(Surface surface)130 public static Size getSurfaceSize(Surface surface) { 131 checkNotNull(surface); 132 133 int[] dimens = new int[2]; 134 int errorFlag = nativeDetectSurfaceDimens(surface, /*out*/dimens); 135 if (errorFlag == BAD_VALUE) throw new IllegalArgumentException("Surface was abandoned"); 136 137 return new Size(dimens[0], dimens[1]); 138 } 139 140 /** 141 * Get the Surface format. 142 * 143 * @param surface The surface to be queried for format. 144 * @return format of the surface. 145 * 146 * @throws IllegalArgumentException if the surface is already abandoned. 147 */ getSurfaceFormat(Surface surface)148 public static int getSurfaceFormat(Surface surface) { 149 checkNotNull(surface); 150 int surfaceType = nativeDetectSurfaceType(surface); 151 if (surfaceType == BAD_VALUE) throw new IllegalArgumentException("Surface was abandoned"); 152 153 // TODO: remove this override since the default format should be 154 // ImageFormat.PRIVATE. b/9487482 155 if ((surfaceType >= PixelFormat.RGBA_8888 156 && surfaceType <= BGRA_8888)) { 157 surfaceType = ImageFormat.PRIVATE; 158 } 159 return surfaceType; 160 } 161 162 /** 163 * Detect and retrieve the Surface format without any 164 * additional overrides. 165 * 166 * @param surface The surface to be queried for format. 167 * @return format of the surface. 168 * 169 * @throws IllegalArgumentException if the surface is already abandoned. 170 */ detectSurfaceFormat(Surface surface)171 public static int detectSurfaceFormat(Surface surface) { 172 checkNotNull(surface); 173 int surfaceType = nativeDetectSurfaceType(surface); 174 if (surfaceType == BAD_VALUE) throw new IllegalArgumentException("Surface was abandoned"); 175 176 return surfaceType; 177 } 178 179 /** 180 * Get the Surface dataspace. 181 * 182 * @param surface The surface to be queried for dataspace. 183 * @return dataspace of the surface. 184 * 185 * @throws IllegalArgumentException if the surface is already abandoned. 186 */ getSurfaceDataspace(Surface surface)187 public static int getSurfaceDataspace(Surface surface) { 188 checkNotNull(surface); 189 int dataSpace = nativeDetectSurfaceDataspace(surface); 190 if (dataSpace == BAD_VALUE) throw new IllegalArgumentException("Surface was abandoned"); 191 return dataSpace; 192 } 193 194 /** 195 * Return true is the consumer is one of the consumers that can accept 196 * producer overrides of the default dimensions and format. 197 * 198 */ isFlexibleConsumer(Surface output)199 public static boolean isFlexibleConsumer(Surface output) { 200 checkNotNull(output); 201 long usageFlags = nativeDetectSurfaceUsageFlags(output); 202 203 // Keep up to date with allowed consumer types in 204 // frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp 205 long disallowedFlags = HardwareBuffer.USAGE_VIDEO_ENCODE | USAGE_RENDERSCRIPT; 206 long allowedFlags = HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE 207 | HardwareBuffer.USAGE_CPU_READ_OFTEN 208 | USAGE_HW_COMPOSER; 209 boolean flexibleConsumer = ((usageFlags & disallowedFlags) == 0 210 && (usageFlags & allowedFlags) != 0); 211 return flexibleConsumer; 212 } 213 214 215 /** 216 * A high speed output surface can only be preview or hardware encoder surface. 217 * 218 * @param surface The high speed output surface to be checked. 219 */ checkHighSpeedSurfaceFormat(Surface surface)220 private static void checkHighSpeedSurfaceFormat(Surface surface) { 221 int surfaceFormat = SurfaceUtils.getSurfaceFormat(surface); 222 223 if (surfaceFormat != ImageFormat.PRIVATE) { 224 throw new IllegalArgumentException("Surface format(" + surfaceFormat + ") is not" 225 + " for preview or hardware video encoding!"); 226 } 227 } 228 229 /** 230 * Verify that that the surfaces are valid for high-speed recording mode, 231 * and that the FPS range is supported 232 * 233 * @param surfaces the surfaces to verify as valid in terms of size and format 234 * @param fpsRange the target high-speed FPS range to validate 235 * @param config The stream configuration map for the device in question 236 */ checkConstrainedHighSpeedSurfaces(Collection<Surface> surfaces, Range<Integer> fpsRange, StreamConfigurationMap config)237 public static void checkConstrainedHighSpeedSurfaces(Collection<Surface> surfaces, 238 Range<Integer> fpsRange, StreamConfigurationMap config) { 239 if (surfaces == null || surfaces.size() == 0 || surfaces.size() > 2) { 240 throw new IllegalArgumentException("Output target surface list must not be null and" 241 + " the size must be 1 or 2"); 242 } 243 244 List<Size> highSpeedSizes = null; 245 if (fpsRange == null) { 246 highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizes()); 247 } else { 248 // Check the FPS range first if provided 249 Range<Integer>[] highSpeedFpsRanges = config.getHighSpeedVideoFpsRanges(); 250 if(!Arrays.asList(highSpeedFpsRanges).contains(fpsRange)) { 251 throw new IllegalArgumentException("Fps range " + fpsRange.toString() + " in the" 252 + " request is not a supported high speed fps range " + 253 Arrays.toString(highSpeedFpsRanges)); 254 } 255 highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizesFor(fpsRange)); 256 } 257 258 for (Surface surface : surfaces) { 259 checkHighSpeedSurfaceFormat(surface); 260 261 // Surface size must be supported high speed sizes. 262 Size surfaceSize = SurfaceUtils.getSurfaceSize(surface); 263 if (!highSpeedSizes.contains(surfaceSize)) { 264 throw new IllegalArgumentException("Surface size " + surfaceSize.toString() + " is" 265 + " not part of the high speed supported size list " + 266 Arrays.toString(highSpeedSizes.toArray())); 267 } 268 // Each output surface must be either preview surface or recording surface. 269 if (!SurfaceUtils.isSurfaceForPreview(surface) && 270 !SurfaceUtils.isSurfaceForHwVideoEncoder(surface)) { 271 throw new IllegalArgumentException("This output surface is neither preview nor " 272 + "hardware video encoding surface"); 273 } 274 if (SurfaceUtils.isSurfaceForPreview(surface) && 275 SurfaceUtils.isSurfaceForHwVideoEncoder(surface)) { 276 throw new IllegalArgumentException("This output surface can not be both preview" 277 + " and hardware video encoding surface"); 278 } 279 } 280 281 // For 2 output surface case, they shouldn't be same type. 282 if (surfaces.size() == 2) { 283 // Up to here, each surface can only be either preview or recording. 284 Iterator<Surface> iterator = surfaces.iterator(); 285 boolean isFirstSurfacePreview = 286 SurfaceUtils.isSurfaceForPreview(iterator.next()); 287 boolean isSecondSurfacePreview = 288 SurfaceUtils.isSurfaceForPreview(iterator.next()); 289 if (isFirstSurfacePreview == isSecondSurfacePreview) { 290 throw new IllegalArgumentException("The 2 output surfaces must have different" 291 + " type"); 292 } 293 } 294 } 295 nativeDetectSurfaceType(Surface surface)296 private static native int nativeDetectSurfaceType(Surface surface); 297 nativeDetectSurfaceDataspace(Surface surface)298 private static native int nativeDetectSurfaceDataspace(Surface surface); 299 nativeDetectSurfaceUsageFlags(Surface surface)300 private static native long nativeDetectSurfaceUsageFlags(Surface surface); 301 nativeDetectSurfaceDimens(Surface surface, int[ ] dimens)302 private static native int nativeDetectSurfaceDimens(Surface surface, 303 /*out*/int[/*2*/] dimens); 304 nativeGetSurfaceId(Surface surface)305 private static native long nativeGetSurfaceId(Surface surface); 306 } 307