Zhijun He | a767772 | 2015-06-01 16:36:06 -0700 | [diff] [blame] | 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 | |
Zhijun He | 47ac349 | 2015-06-10 14:41:57 -0700 | [diff] [blame] | 19 | import android.graphics.ImageFormat; |
Zhijun He | a767772 | 2015-06-01 16:36:06 -0700 | [diff] [blame] | 20 | import android.hardware.camera2.legacy.LegacyCameraDevice; |
| 21 | import android.hardware.camera2.legacy.LegacyExceptionUtils.BufferQueueAbandonedException; |
Eino-Ville Talvala | 639fffe | 2015-06-30 10:34:48 -0700 | [diff] [blame] | 22 | import android.hardware.camera2.params.StreamConfigurationMap; |
| 23 | import android.util.Range; |
Zhijun He | a767772 | 2015-06-01 16:36:06 -0700 | [diff] [blame] | 24 | import android.util.Size; |
| 25 | import android.view.Surface; |
| 26 | |
Eino-Ville Talvala | 639fffe | 2015-06-30 10:34:48 -0700 | [diff] [blame] | 27 | import java.util.Arrays; |
| 28 | import java.util.Collection; |
| 29 | import java.util.Iterator; |
| 30 | import java.util.List; |
| 31 | |
Zhijun He | a767772 | 2015-06-01 16:36:06 -0700 | [diff] [blame] | 32 | /** |
| 33 | * Various Surface utilities. |
| 34 | */ |
| 35 | public class SurfaceUtils { |
| 36 | |
| 37 | /** |
Zhijun He | 47ac349 | 2015-06-10 14:41:57 -0700 | [diff] [blame] | 38 | * Check if a surface is for preview consumer based on consumer end point Gralloc usage flags. |
Zhijun He | a767772 | 2015-06-01 16:36:06 -0700 | [diff] [blame] | 39 | * |
| 40 | * @param surface The surface to be checked. |
| 41 | * @return true if the surface is for preview consumer, false otherwise. |
| 42 | */ |
| 43 | public static boolean isSurfaceForPreview(Surface surface) { |
| 44 | return LegacyCameraDevice.isPreviewConsumer(surface); |
| 45 | } |
| 46 | |
| 47 | /** |
Zhijun He | 47ac349 | 2015-06-10 14:41:57 -0700 | [diff] [blame] | 48 | * Check if the surface is for hardware video encoder consumer based on consumer end point |
| 49 | * Gralloc usage flags. |
Zhijun He | a767772 | 2015-06-01 16:36:06 -0700 | [diff] [blame] | 50 | * |
| 51 | * @param surface The surface to be checked. |
| 52 | * @return true if the surface is for hardware video encoder consumer, false otherwise. |
| 53 | */ |
| 54 | public static boolean isSurfaceForHwVideoEncoder(Surface surface) { |
| 55 | return LegacyCameraDevice.isVideoEncoderConsumer(surface); |
| 56 | } |
| 57 | |
| 58 | /** |
Yin-Chia Yeh | 4f15147 | 2018-02-21 12:38:19 -0800 | [diff] [blame] | 59 | * Get the native object id of a surface. |
| 60 | * |
| 61 | * @param surface The surface to be checked. |
| 62 | * @return the native object id of the surface, 0 if surface is not backed by a native object. |
| 63 | */ |
| 64 | public static long getSurfaceId(Surface surface) { |
| 65 | try { |
| 66 | return LegacyCameraDevice.getSurfaceId(surface); |
| 67 | } catch (BufferQueueAbandonedException e) { |
| 68 | return 0; |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | /** |
Zhijun He | a767772 | 2015-06-01 16:36:06 -0700 | [diff] [blame] | 73 | * Get the Surface size. |
| 74 | * |
| 75 | * @param surface The surface to be queried for size. |
| 76 | * @return Size of the surface. |
| 77 | * |
Zhijun He | 39d1461 | 2015-06-04 20:21:23 -0700 | [diff] [blame] | 78 | * @throws IllegalArgumentException if the surface is already abandoned. |
Zhijun He | a767772 | 2015-06-01 16:36:06 -0700 | [diff] [blame] | 79 | */ |
| 80 | public static Size getSurfaceSize(Surface surface) { |
| 81 | try { |
| 82 | return LegacyCameraDevice.getSurfaceSize(surface); |
| 83 | } catch (BufferQueueAbandonedException e) { |
| 84 | throw new IllegalArgumentException("Surface was abandoned", e); |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | /** |
| 89 | * Get the Surface format. |
| 90 | * |
| 91 | * @param surface The surface to be queried for format. |
| 92 | * @return format of the surface. |
| 93 | * |
Zhijun He | 39d1461 | 2015-06-04 20:21:23 -0700 | [diff] [blame] | 94 | * @throws IllegalArgumentException if the surface is already abandoned. |
Zhijun He | a767772 | 2015-06-01 16:36:06 -0700 | [diff] [blame] | 95 | */ |
| 96 | public static int getSurfaceFormat(Surface surface) { |
| 97 | try { |
| 98 | return LegacyCameraDevice.detectSurfaceType(surface); |
| 99 | } catch (BufferQueueAbandonedException e) { |
| 100 | throw new IllegalArgumentException("Surface was abandoned", e); |
| 101 | } |
| 102 | } |
Eino-Ville Talvala | e365120 | 2015-06-19 17:29:14 -0700 | [diff] [blame] | 103 | |
| 104 | /** |
| 105 | * Get the Surface dataspace. |
| 106 | * |
| 107 | * @param surface The surface to be queried for dataspace. |
| 108 | * @return dataspace of the surface. |
| 109 | * |
| 110 | * @throws IllegalArgumentException if the surface is already abandoned. |
| 111 | */ |
| 112 | public static int getSurfaceDataspace(Surface surface) { |
| 113 | try { |
| 114 | return LegacyCameraDevice.detectSurfaceDataspace(surface); |
| 115 | } catch (BufferQueueAbandonedException e) { |
| 116 | throw new IllegalArgumentException("Surface was abandoned", e); |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | /** |
| 121 | * Return true is the consumer is one of the consumers that can accept |
| 122 | * producer overrides of the default dimensions and format. |
| 123 | * |
| 124 | */ |
| 125 | public static boolean isFlexibleConsumer(Surface output) { |
| 126 | return LegacyCameraDevice.isFlexibleConsumer(output); |
| 127 | } |
| 128 | |
Eino-Ville Talvala | 639fffe | 2015-06-30 10:34:48 -0700 | [diff] [blame] | 129 | /** |
| 130 | * A high speed output surface can only be preview or hardware encoder surface. |
| 131 | * |
| 132 | * @param surface The high speed output surface to be checked. |
| 133 | */ |
| 134 | private static void checkHighSpeedSurfaceFormat(Surface surface) { |
Eino-Ville Talvala | 639fffe | 2015-06-30 10:34:48 -0700 | [diff] [blame] | 135 | int surfaceFormat = SurfaceUtils.getSurfaceFormat(surface); |
Eino-Ville Talvala | 639fffe | 2015-06-30 10:34:48 -0700 | [diff] [blame] | 136 | |
| 137 | if (surfaceFormat != ImageFormat.PRIVATE) { |
| 138 | throw new IllegalArgumentException("Surface format(" + surfaceFormat + ") is not" |
| 139 | + " for preview or hardware video encoding!"); |
| 140 | } |
| 141 | } |
| 142 | |
| 143 | /** |
| 144 | * Verify that that the surfaces are valid for high-speed recording mode, |
| 145 | * and that the FPS range is supported |
| 146 | * |
| 147 | * @param surfaces the surfaces to verify as valid in terms of size and format |
| 148 | * @param fpsRange the target high-speed FPS range to validate |
| 149 | * @param config The stream configuration map for the device in question |
| 150 | */ |
| 151 | public static void checkConstrainedHighSpeedSurfaces(Collection<Surface> surfaces, |
| 152 | Range<Integer> fpsRange, StreamConfigurationMap config) { |
| 153 | if (surfaces == null || surfaces.size() == 0 || surfaces.size() > 2) { |
| 154 | throw new IllegalArgumentException("Output target surface list must not be null and" |
| 155 | + " the size must be 1 or 2"); |
| 156 | } |
| 157 | |
| 158 | List<Size> highSpeedSizes = null; |
| 159 | if (fpsRange == null) { |
| 160 | highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizes()); |
| 161 | } else { |
| 162 | // Check the FPS range first if provided |
| 163 | Range<Integer>[] highSpeedFpsRanges = config.getHighSpeedVideoFpsRanges(); |
| 164 | if(!Arrays.asList(highSpeedFpsRanges).contains(fpsRange)) { |
| 165 | throw new IllegalArgumentException("Fps range " + fpsRange.toString() + " in the" |
| 166 | + " request is not a supported high speed fps range " + |
| 167 | Arrays.toString(highSpeedFpsRanges)); |
| 168 | } |
| 169 | highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizesFor(fpsRange)); |
| 170 | } |
| 171 | |
| 172 | for (Surface surface : surfaces) { |
| 173 | checkHighSpeedSurfaceFormat(surface); |
| 174 | |
| 175 | // Surface size must be supported high speed sizes. |
| 176 | Size surfaceSize = SurfaceUtils.getSurfaceSize(surface); |
| 177 | if (!highSpeedSizes.contains(surfaceSize)) { |
| 178 | throw new IllegalArgumentException("Surface size " + surfaceSize.toString() + " is" |
| 179 | + " not part of the high speed supported size list " + |
| 180 | Arrays.toString(highSpeedSizes.toArray())); |
| 181 | } |
| 182 | // Each output surface must be either preview surface or recording surface. |
| 183 | if (!SurfaceUtils.isSurfaceForPreview(surface) && |
| 184 | !SurfaceUtils.isSurfaceForHwVideoEncoder(surface)) { |
| 185 | throw new IllegalArgumentException("This output surface is neither preview nor " |
| 186 | + "hardware video encoding surface"); |
| 187 | } |
| 188 | if (SurfaceUtils.isSurfaceForPreview(surface) && |
| 189 | SurfaceUtils.isSurfaceForHwVideoEncoder(surface)) { |
| 190 | throw new IllegalArgumentException("This output surface can not be both preview" |
| 191 | + " and hardware video encoding surface"); |
| 192 | } |
| 193 | } |
| 194 | |
| 195 | // For 2 output surface case, they shouldn't be same type. |
| 196 | if (surfaces.size() == 2) { |
| 197 | // Up to here, each surface can only be either preview or recording. |
| 198 | Iterator<Surface> iterator = surfaces.iterator(); |
| 199 | boolean isFirstSurfacePreview = |
| 200 | SurfaceUtils.isSurfaceForPreview(iterator.next()); |
| 201 | boolean isSecondSurfacePreview = |
| 202 | SurfaceUtils.isSurfaceForPreview(iterator.next()); |
| 203 | if (isFirstSurfacePreview == isSecondSurfacePreview) { |
| 204 | throw new IllegalArgumentException("The 2 output surfaces must have different" |
| 205 | + " type"); |
| 206 | } |
| 207 | } |
| 208 | } |
| 209 | |
Zhijun He | a767772 | 2015-06-01 16:36:06 -0700 | [diff] [blame] | 210 | } |