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