blob: 92478441aea30333c63c72ab7a0ffd1b70934403 [file] [log] [blame]
Zhijun Hea7677722015-06-01 16:36:06 -07001/*
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
17package android.hardware.camera2.utils;
18
Zhijun He47ac3492015-06-10 14:41:57 -070019import android.graphics.ImageFormat;
Zhijun Hea7677722015-06-01 16:36:06 -070020import android.hardware.camera2.legacy.LegacyCameraDevice;
21import android.hardware.camera2.legacy.LegacyExceptionUtils.BufferQueueAbandonedException;
Eino-Ville Talvala639fffe2015-06-30 10:34:48 -070022import android.hardware.camera2.params.StreamConfigurationMap;
23import android.util.Range;
Zhijun Hea7677722015-06-01 16:36:06 -070024import android.util.Size;
25import android.view.Surface;
26
Eino-Ville Talvala639fffe2015-06-30 10:34:48 -070027import java.util.Arrays;
28import java.util.Collection;
29import java.util.Iterator;
30import java.util.List;
31
Zhijun Hea7677722015-06-01 16:36:06 -070032/**
33 * Various Surface utilities.
34 */
35public class SurfaceUtils {
36
37 /**
Zhijun He47ac3492015-06-10 14:41:57 -070038 * Check if a surface is for preview consumer based on consumer end point Gralloc usage flags.
Zhijun Hea7677722015-06-01 16:36:06 -070039 *
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 He47ac3492015-06-10 14:41:57 -070048 * Check if the surface is for hardware video encoder consumer based on consumer end point
49 * Gralloc usage flags.
Zhijun Hea7677722015-06-01 16:36:06 -070050 *
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 Yeh4f151472018-02-21 12:38:19 -080059 * 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 Hea7677722015-06-01 16:36:06 -070073 * Get the Surface size.
74 *
75 * @param surface The surface to be queried for size.
76 * @return Size of the surface.
77 *
Zhijun He39d14612015-06-04 20:21:23 -070078 * @throws IllegalArgumentException if the surface is already abandoned.
Zhijun Hea7677722015-06-01 16:36:06 -070079 */
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 He39d14612015-06-04 20:21:23 -070094 * @throws IllegalArgumentException if the surface is already abandoned.
Zhijun Hea7677722015-06-01 16:36:06 -070095 */
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 Talvalae3651202015-06-19 17:29:14 -0700103
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 Talvala639fffe2015-06-30 10:34:48 -0700129 /**
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 Talvala639fffe2015-06-30 10:34:48 -0700135 int surfaceFormat = SurfaceUtils.getSurfaceFormat(surface);
Eino-Ville Talvala639fffe2015-06-30 10:34:48 -0700136
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 Hea7677722015-06-01 16:36:06 -0700210}