1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
/*
* Copyright 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.camera2.utils;
import android.graphics.ImageFormat;
import android.hardware.camera2.legacy.LegacyCameraDevice;
import android.hardware.camera2.legacy.LegacyExceptionUtils.BufferQueueAbandonedException;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.util.Range;
import android.util.Size;
import android.view.Surface;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
/**
* Various Surface utilities.
*/
public class SurfaceUtils {
/**
* Check if a surface is for preview consumer based on consumer end point Gralloc usage flags.
*
* @param surface The surface to be checked.
* @return true if the surface is for preview consumer, false otherwise.
*/
public static boolean isSurfaceForPreview(Surface surface) {
return LegacyCameraDevice.isPreviewConsumer(surface);
}
/**
* Check if the surface is for hardware video encoder consumer based on consumer end point
* Gralloc usage flags.
*
* @param surface The surface to be checked.
* @return true if the surface is for hardware video encoder consumer, false otherwise.
*/
public static boolean isSurfaceForHwVideoEncoder(Surface surface) {
return LegacyCameraDevice.isVideoEncoderConsumer(surface);
}
/**
* Get the Surface size.
*
* @param surface The surface to be queried for size.
* @return Size of the surface.
*
* @throws IllegalArgumentException if the surface is already abandoned.
*/
public static Size getSurfaceSize(Surface surface) {
try {
return LegacyCameraDevice.getSurfaceSize(surface);
} catch (BufferQueueAbandonedException e) {
throw new IllegalArgumentException("Surface was abandoned", e);
}
}
/**
* Get the Surface format.
*
* @param surface The surface to be queried for format.
* @return format of the surface.
*
* @throws IllegalArgumentException if the surface is already abandoned.
*/
public static int getSurfaceFormat(Surface surface) {
try {
return LegacyCameraDevice.detectSurfaceType(surface);
} catch (BufferQueueAbandonedException e) {
throw new IllegalArgumentException("Surface was abandoned", e);
}
}
/**
* Get the Surface dataspace.
*
* @param surface The surface to be queried for dataspace.
* @return dataspace of the surface.
*
* @throws IllegalArgumentException if the surface is already abandoned.
*/
public static int getSurfaceDataspace(Surface surface) {
try {
return LegacyCameraDevice.detectSurfaceDataspace(surface);
} catch (BufferQueueAbandonedException e) {
throw new IllegalArgumentException("Surface was abandoned", e);
}
}
/**
* Return true is the consumer is one of the consumers that can accept
* producer overrides of the default dimensions and format.
*
*/
public static boolean isFlexibleConsumer(Surface output) {
return LegacyCameraDevice.isFlexibleConsumer(output);
}
/**
* A high speed output surface can only be preview or hardware encoder surface.
*
* @param surface The high speed output surface to be checked.
*/
private static void checkHighSpeedSurfaceFormat(Surface surface) {
// TODO: remove this override since the default format should be
// ImageFormat.PRIVATE. b/9487482
final int HAL_FORMAT_RGB_START = 1; // HAL_PIXEL_FORMAT_RGBA_8888 from graphics.h
final int HAL_FORMAT_RGB_END = 5; // HAL_PIXEL_FORMAT_BGRA_8888 from graphics.h
int surfaceFormat = SurfaceUtils.getSurfaceFormat(surface);
if (surfaceFormat >= HAL_FORMAT_RGB_START &&
surfaceFormat <= HAL_FORMAT_RGB_END) {
surfaceFormat = ImageFormat.PRIVATE;
}
if (surfaceFormat != ImageFormat.PRIVATE) {
throw new IllegalArgumentException("Surface format(" + surfaceFormat + ") is not"
+ " for preview or hardware video encoding!");
}
}
/**
* Verify that that the surfaces are valid for high-speed recording mode,
* and that the FPS range is supported
*
* @param surfaces the surfaces to verify as valid in terms of size and format
* @param fpsRange the target high-speed FPS range to validate
* @param config The stream configuration map for the device in question
*/
public static void checkConstrainedHighSpeedSurfaces(Collection<Surface> surfaces,
Range<Integer> fpsRange, StreamConfigurationMap config) {
if (surfaces == null || surfaces.size() == 0 || surfaces.size() > 2) {
throw new IllegalArgumentException("Output target surface list must not be null and"
+ " the size must be 1 or 2");
}
List<Size> highSpeedSizes = null;
if (fpsRange == null) {
highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizes());
} else {
// Check the FPS range first if provided
Range<Integer>[] highSpeedFpsRanges = config.getHighSpeedVideoFpsRanges();
if(!Arrays.asList(highSpeedFpsRanges).contains(fpsRange)) {
throw new IllegalArgumentException("Fps range " + fpsRange.toString() + " in the"
+ " request is not a supported high speed fps range " +
Arrays.toString(highSpeedFpsRanges));
}
highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizesFor(fpsRange));
}
for (Surface surface : surfaces) {
checkHighSpeedSurfaceFormat(surface);
// Surface size must be supported high speed sizes.
Size surfaceSize = SurfaceUtils.getSurfaceSize(surface);
if (!highSpeedSizes.contains(surfaceSize)) {
throw new IllegalArgumentException("Surface size " + surfaceSize.toString() + " is"
+ " not part of the high speed supported size list " +
Arrays.toString(highSpeedSizes.toArray()));
}
// Each output surface must be either preview surface or recording surface.
if (!SurfaceUtils.isSurfaceForPreview(surface) &&
!SurfaceUtils.isSurfaceForHwVideoEncoder(surface)) {
throw new IllegalArgumentException("This output surface is neither preview nor "
+ "hardware video encoding surface");
}
if (SurfaceUtils.isSurfaceForPreview(surface) &&
SurfaceUtils.isSurfaceForHwVideoEncoder(surface)) {
throw new IllegalArgumentException("This output surface can not be both preview"
+ " and hardware video encoding surface");
}
}
// For 2 output surface case, they shouldn't be same type.
if (surfaces.size() == 2) {
// Up to here, each surface can only be either preview or recording.
Iterator<Surface> iterator = surfaces.iterator();
boolean isFirstSurfacePreview =
SurfaceUtils.isSurfaceForPreview(iterator.next());
boolean isSecondSurfacePreview =
SurfaceUtils.isSurfaceForPreview(iterator.next());
if (isFirstSurfacePreview == isSecondSurfacePreview) {
throw new IllegalArgumentException("The 2 output surfaces must have different"
+ " type");
}
}
}
}
|