blob: a040a09cf4698b7d25a82456cac7529667aaaab9 [file] [log] [blame]
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -07001/*
2 * Copyright (C) 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
18package android.hardware.camera2.params;
19
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -070020import android.annotation.NonNull;
21import android.annotation.Nullable;
Zhijun He445b3162016-01-18 15:34:28 -080022import android.annotation.SystemApi;
Zhijun Hec8b181e2016-05-30 14:54:39 -070023import android.graphics.ImageFormat;
24import android.hardware.camera2.CameraCaptureSession;
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -070025import android.hardware.camera2.CameraDevice;
Yin-Chia Yeh61f15362015-04-03 10:46:25 -070026import android.hardware.camera2.utils.HashCodeHelpers;
Chien-Yu Chen828adbb2015-08-18 12:46:39 -070027import android.hardware.camera2.utils.SurfaceUtils;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -080028import android.os.Parcel;
29import android.os.Parcelable;
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -070030import android.util.Log;
Chien-Yu Chen828adbb2015-08-18 12:46:39 -070031import android.util.Size;
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -070032import android.view.Surface;
33
34import static com.android.internal.util.Preconditions.*;
35
Shuzhen Wang23d29382017-11-26 17:24:56 -080036import java.util.ArrayList;
37import java.util.Collections;
38import java.util.List;
39
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -070040/**
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -070041 * A class for describing camera output, which contains a {@link Surface} and its specific
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -070042 * configuration for creating capture session.
43 *
Emilian Peev03233152017-10-27 16:01:20 +010044 * <p>There are several ways to instantiate, modify and use OutputConfigurations. The most common
45 * and recommended usage patterns are summarized in the following list:</p>
46 *<ul>
47 * <li>Passing a {@link Surface} to the constructor and using the OutputConfiguration instance as
48 * argument to {@link CameraDevice#createCaptureSessionByOutputConfigurations}. This is the most
49 * frequent usage and clients should consider it first before other more complicated alternatives.
50 * </li>
51 *
52 * <li>Passing only a surface source class as an argument to the constructor. This is usually
53 * followed by a call to create a capture session
54 * (see {@link CameraDevice#createCaptureSessionByOutputConfigurations} and a {@link Surface} add
55 * call {@link #addSurface} with a valid {@link Surface}. The sequence completes with
56 * {@link CameraCaptureSession#finalizeOutputConfigurations}. This is the deferred usage case which
57 * aims to enhance performance by allowing the resource-intensive capture session create call to
58 * execute in parallel with any {@link Surface} initialization, such as waiting for a
59 * {@link android.view.SurfaceView} to be ready as part of the UI initialization.</li>
60 *
61 * <li>The third and most complex usage pattern inlvolves surface sharing. Once instantiated an
62 * OutputConfiguration can be enabled for surface sharing via {@link #enableSurfaceSharing}. This
63 * must be done before creating a new capture session and enables calls to
64 * {@link CameraCaptureSession#updateOutputConfiguration}. An OutputConfiguration with enabled
65 * surface sharing can be modified via {@link #addSurface} or {@link #removeSurface}. The updates
66 * to this OutputConfiguration will only come into effect after
67 * {@link CameraCaptureSession#updateOutputConfiguration} returns without throwing exceptions.
68 * Such updates can be done as long as the session is active. Clients should always consider the
69 * additional requirements and limitations placed on the output surfaces (for more details see
70 * {@link #enableSurfaceSharing}, {@link #addSurface}, {@link #removeSurface},
71 * {@link CameraCaptureSession#updateOutputConfiguration}). A trade-off exists between additional
72 * complexity and flexibility. If exercised correctly surface sharing can switch between different
73 * output surfaces without interrupting any ongoing repeating capture requests. This saves time and
74 * can significantly improve the user experience.</li>
75 *
76 * <li>Surface sharing can be used in combination with deferred surfaces. The rules from both cases
77 * are combined and clients must call {@link #enableSurfaceSharing} before creating a capture
78 * session. Attach and/or remove output surfaces via {@link #addSurface}/{@link #removeSurface} and
79 * finalize the configuration using {@link CameraCaptureSession#finalizeOutputConfigurations}.
80 * {@link CameraCaptureSession#updateOutputConfiguration} can be called after the configuration
81 * finalize method returns without exceptions.</li>
82 *
83 * </ul>
84 *
Emilian Peev5c19a992018-02-12 22:33:44 +000085 * <p> As of {@link android.os.Build.VERSION_CODES#P Android P}, all formats can be used for
86 * sharing, subject to device support. On prior API levels, only {@link ImageFormat#PRIVATE}
87 * format may be used.</p>
Emilian Peev03233152017-10-27 16:01:20 +010088 *
Shuzhen Wang9c663d42016-10-28 23:25:02 -070089 * @see CameraDevice#createCaptureSessionByOutputConfigurations
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -070090 *
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -070091 */
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -070092public final class OutputConfiguration implements Parcelable {
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -070093
94 /**
95 * Rotation constant: 0 degree rotation (no rotation)
Zhijun He445b3162016-01-18 15:34:28 -080096 *
97 * @hide
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -070098 */
Zhijun He445b3162016-01-18 15:34:28 -080099 @SystemApi
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700100 public static final int ROTATION_0 = 0;
101
102 /**
103 * Rotation constant: 90 degree counterclockwise rotation.
Zhijun He445b3162016-01-18 15:34:28 -0800104 *
105 * @hide
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700106 */
Zhijun He445b3162016-01-18 15:34:28 -0800107 @SystemApi
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700108 public static final int ROTATION_90 = 1;
109
110 /**
111 * Rotation constant: 180 degree counterclockwise rotation.
Zhijun He445b3162016-01-18 15:34:28 -0800112 *
113 * @hide
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700114 */
Zhijun He445b3162016-01-18 15:34:28 -0800115 @SystemApi
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700116 public static final int ROTATION_180 = 2;
117
118 /**
119 * Rotation constant: 270 degree counterclockwise rotation.
Zhijun He445b3162016-01-18 15:34:28 -0800120 *
121 * @hide
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700122 */
Zhijun He445b3162016-01-18 15:34:28 -0800123 @SystemApi
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700124 public static final int ROTATION_270 = 3;
125
126 /**
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700127 * Invalid surface group ID.
Zhijun He445b3162016-01-18 15:34:28 -0800128 *
129 *<p>An {@link OutputConfiguration} with this value indicates that the included surface
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700130 *doesn't belong to any surface group.</p>
Zhijun He445b3162016-01-18 15:34:28 -0800131 */
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700132 public static final int SURFACE_GROUP_ID_NONE = -1;
Zhijun He445b3162016-01-18 15:34:28 -0800133
134 /**
135 * Create a new {@link OutputConfiguration} instance with a {@link Surface}.
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700136 *
137 * @param surface
138 * A Surface for camera to output to.
139 *
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700140 * <p>This constructor creates a default configuration, with a surface group ID of
141 * {@value #SURFACE_GROUP_ID_NONE}.</p>
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700142 *
143 */
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700144 public OutputConfiguration(@NonNull Surface surface) {
145 this(SURFACE_GROUP_ID_NONE, surface, ROTATION_0);
146 }
147
148 /**
Zhijun Hec8b181e2016-05-30 14:54:39 -0700149 * Unknown surface source type.
150 */
151 private final int SURFACE_TYPE_UNKNOWN = -1;
152
153 /**
154 * The surface is obtained from {@link android.view.SurfaceView}.
155 */
156 private final int SURFACE_TYPE_SURFACE_VIEW = 0;
157
158 /**
159 * The surface is obtained from {@link android.graphics.SurfaceTexture}.
160 */
161 private final int SURFACE_TYPE_SURFACE_TEXTURE = 1;
162
163 /**
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800164 * Maximum number of surfaces supported by one {@link OutputConfiguration}.
165 *
166 * <p>The combined number of surfaces added by the constructor and
167 * {@link OutputConfiguration#addSurface} should not exceed this value.</p>
168 *
169 */
Emilian Peev03233152017-10-27 16:01:20 +0100170 private static final int MAX_SURFACES_COUNT = 4;
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800171
172 /**
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700173 * Create a new {@link OutputConfiguration} instance with a {@link Surface},
174 * with a surface group ID.
175 *
176 * <p>
177 * A surface group ID is used to identify which surface group this output surface belongs to. A
178 * surface group is a group of output surfaces that are not intended to receive camera output
179 * buffer streams simultaneously. The {@link CameraDevice} may be able to share the buffers used
180 * by all the surfaces from the same surface group, therefore may reduce the overall memory
181 * footprint. The application should only set the same set ID for the streams that are not
182 * simultaneously streaming. A negative ID indicates that this surface doesn't belong to any
183 * surface group. The default value is {@value #SURFACE_GROUP_ID_NONE}.</p>
184 *
185 * <p>For example, a video chat application that has an adaptive output resolution feature would
186 * need two (or more) output resolutions, to switch resolutions without any output glitches.
187 * However, at any given time, only one output is active to minimize outgoing network bandwidth
188 * and encoding overhead. To save memory, the application should set the video outputs to have
189 * the same non-negative group ID, so that the camera device can share the same memory region
190 * for the alternating outputs.</p>
191 *
192 * <p>It is not an error to include output streams with the same group ID in the same capture
193 * request, but the resulting memory consumption may be higher than if the two streams were
194 * not in the same surface group to begin with, especially if the outputs have substantially
195 * different dimensions.</p>
196 *
197 * @param surfaceGroupId
198 * A group ID for this output, used for sharing memory between multiple outputs.
199 * @param surface
200 * A Surface for camera to output to.
201 *
202 */
203 public OutputConfiguration(int surfaceGroupId, @NonNull Surface surface) {
204 this(surfaceGroupId, surface, ROTATION_0);
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700205 }
206
207 /**
Zhijun He445b3162016-01-18 15:34:28 -0800208 * Create a new {@link OutputConfiguration} instance.
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700209 *
210 * <p>This constructor takes an argument for desired camera rotation</p>
211 *
212 * @param surface
213 * A Surface for camera to output to.
214 * @param rotation
215 * The desired rotation to be applied on camera output. Value must be one of
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700216 * ROTATION_[0, 90, 180, 270]. Note that when the rotation is 90 or 270 degrees,
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700217 * application should make sure corresponding surface size has width and height
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700218 * transposed relative to the width and height without rotation. For example,
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700219 * if application needs camera to capture 1280x720 picture and rotate it by 90 degree,
220 * application should set rotation to {@code ROTATION_90} and make sure the
221 * corresponding Surface size is 720x1280. Note that {@link CameraDevice} might
222 * throw {@code IllegalArgumentException} if device cannot perform such rotation.
Zhijun He445b3162016-01-18 15:34:28 -0800223 * @hide
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700224 */
Zhijun He445b3162016-01-18 15:34:28 -0800225 @SystemApi
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700226 public OutputConfiguration(@NonNull Surface surface, int rotation) {
227 this(SURFACE_GROUP_ID_NONE, surface, rotation);
228 }
229
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700230 /**
231 * Create a new {@link OutputConfiguration} instance, with rotation and a group ID.
232 *
233 * <p>This constructor takes an argument for desired camera rotation and for the surface group
234 * ID. See {@link #OutputConfiguration(int, Surface)} for details of the group ID.</p>
235 *
236 * @param surfaceGroupId
237 * A group ID for this output, used for sharing memory between multiple outputs.
238 * @param surface
239 * A Surface for camera to output to.
240 * @param rotation
241 * The desired rotation to be applied on camera output. Value must be one of
242 * ROTATION_[0, 90, 180, 270]. Note that when the rotation is 90 or 270 degrees,
243 * application should make sure corresponding surface size has width and height
244 * transposed relative to the width and height without rotation. For example,
245 * if application needs camera to capture 1280x720 picture and rotate it by 90 degree,
246 * application should set rotation to {@code ROTATION_90} and make sure the
247 * corresponding Surface size is 720x1280. Note that {@link CameraDevice} might
248 * throw {@code IllegalArgumentException} if device cannot perform such rotation.
249 * @hide
250 */
251 @SystemApi
252 public OutputConfiguration(int surfaceGroupId, @NonNull Surface surface, int rotation) {
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700253 checkNotNull(surface, "Surface must not be null");
254 checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700255 mSurfaceGroupId = surfaceGroupId;
Zhijun Hec8b181e2016-05-30 14:54:39 -0700256 mSurfaceType = SURFACE_TYPE_UNKNOWN;
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800257 mSurfaces = new ArrayList<Surface>();
258 mSurfaces.add(surface);
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700259 mRotation = rotation;
Chien-Yu Chen828adbb2015-08-18 12:46:39 -0700260 mConfiguredSize = SurfaceUtils.getSurfaceSize(surface);
261 mConfiguredFormat = SurfaceUtils.getSurfaceFormat(surface);
262 mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(surface);
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700263 mConfiguredGenerationId = surface.getGenerationId();
Zhijun Hec8b181e2016-05-30 14:54:39 -0700264 mIsDeferredConfig = false;
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800265 mIsShared = false;
Shuzhen Wang23d29382017-11-26 17:24:56 -0800266 mPhysicalCameraId = null;
Zhijun Hec8b181e2016-05-30 14:54:39 -0700267 }
268
269 /**
270 * Create a new {@link OutputConfiguration} instance, with desired Surface size and Surface
271 * source class.
272 * <p>
273 * This constructor takes an argument for desired Surface size and the Surface source class
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800274 * without providing the actual output Surface. This is used to setup an output configuration
Zhijun Hec8b181e2016-05-30 14:54:39 -0700275 * with a deferred Surface. The application can use this output configuration to create a
276 * session.
277 * </p>
278 * <p>
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800279 * However, the actual output Surface must be set via {@link #addSurface} and the deferred
280 * Surface configuration must be finalized via {@link
281 * CameraCaptureSession#finalizeOutputConfigurations} before submitting a request with this
282 * Surface target. The deferred Surface can only be obtained either from {@link
283 * android.view.SurfaceView} by calling {@link android.view.SurfaceHolder#getSurface}, or from
Zhijun Hec8b181e2016-05-30 14:54:39 -0700284 * {@link android.graphics.SurfaceTexture} via
285 * {@link android.view.Surface#Surface(android.graphics.SurfaceTexture)}).
286 * </p>
287 *
288 * @param surfaceSize Size for the deferred surface.
289 * @param klass a non-{@code null} {@link Class} object reference that indicates the source of
290 * this surface. Only {@link android.view.SurfaceHolder SurfaceHolder.class} and
291 * {@link android.graphics.SurfaceTexture SurfaceTexture.class} are supported.
Shuzhen Wang21d63b22017-01-27 22:32:26 -0800292 * @throws IllegalArgumentException if the Surface source class is not supported, or Surface
293 * size is zero.
Zhijun Hec8b181e2016-05-30 14:54:39 -0700294 */
295 public <T> OutputConfiguration(@NonNull Size surfaceSize, @NonNull Class<T> klass) {
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800296 checkNotNull(klass, "surfaceSize must not be null");
297 checkNotNull(klass, "klass must not be null");
298 if (klass == android.view.SurfaceHolder.class) {
299 mSurfaceType = SURFACE_TYPE_SURFACE_VIEW;
300 } else if (klass == android.graphics.SurfaceTexture.class) {
301 mSurfaceType = SURFACE_TYPE_SURFACE_TEXTURE;
302 } else {
303 mSurfaceType = SURFACE_TYPE_UNKNOWN;
304 throw new IllegalArgumentException("Unknow surface source class type");
305 }
Zhijun Hec8b181e2016-05-30 14:54:39 -0700306
Shuzhen Wang476bea82017-02-09 13:13:04 -0800307 if (surfaceSize.getWidth() == 0 || surfaceSize.getHeight() == 0) {
308 throw new IllegalArgumentException("Surface size needs to be non-zero");
309 }
310
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800311 mSurfaceGroupId = SURFACE_GROUP_ID_NONE;
312 mSurfaces = new ArrayList<Surface>();
313 mRotation = ROTATION_0;
314 mConfiguredSize = surfaceSize;
315 mConfiguredFormat = StreamConfigurationMap.imageFormatToInternal(ImageFormat.PRIVATE);
316 mConfiguredDataspace = StreamConfigurationMap.imageFormatToDataspace(ImageFormat.PRIVATE);
317 mConfiguredGenerationId = 0;
318 mIsDeferredConfig = true;
319 mIsShared = false;
Shuzhen Wang23d29382017-11-26 17:24:56 -0800320 mPhysicalCameraId = null;
Shuzhen Wang9c663d42016-10-28 23:25:02 -0700321 }
322
323 /**
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800324 * Enable multiple surfaces sharing the same OutputConfiguration
Shuzhen Wang9c663d42016-10-28 23:25:02 -0700325 *
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800326 * <p>For advanced use cases, a camera application may require more streams than the combination
327 * guaranteed by {@link CameraDevice#createCaptureSession}. In this case, more than one
328 * compatible surface can be attached to an OutputConfiguration so that they map to one
Emilian Peev03233152017-10-27 16:01:20 +0100329 * camera stream, and the outputs share memory buffers when possible. Due to buffer sharing
330 * clients should be careful when adding surface outputs that modify their input data. If such
331 * case exists, camera clients should have an additional mechanism to synchronize read and write
332 * access between individual consumers.</p>
Shuzhen Wang9c663d42016-10-28 23:25:02 -0700333 *
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800334 * <p>Two surfaces are compatible in the below cases:</p>
Shuzhen Wang9c663d42016-10-28 23:25:02 -0700335 *
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800336 * <li> Surfaces with the same size, format, dataSpace, and Surface source class. In this case,
337 * {@link CameraDevice#createCaptureSessionByOutputConfigurations} is guaranteed to succeed.
338 *
339 * <li> Surfaces with the same size, format, and dataSpace, but different Surface source classes
340 * that are generally not compatible. However, on some devices, the underlying camera device is
341 * able to use the same buffer layout for both surfaces. The only way to discover if this is the
342 * case is to create a capture session with that output configuration. For example, if the
343 * camera device uses the same private buffer format between a SurfaceView/SurfaceTexture and a
344 * MediaRecorder/MediaCodec, {@link CameraDevice#createCaptureSessionByOutputConfigurations}
Shuzhen Wangf02913c2017-01-31 15:33:41 -0800345 * will succeed. Otherwise, it fails with {@link
346 * CameraCaptureSession.StateCallback#onConfigureFailed}.
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800347 * </ol>
348 *
349 * <p>To enable surface sharing, this function must be called before {@link
Shuzhen Wang23d29382017-11-26 17:24:56 -0800350 * CameraDevice#createCaptureSessionByOutputConfigurations} or {@link
351 * CameraDevice#createReprocessableCaptureSessionByConfigurations}. Calling this function after
352 * {@link CameraDevice#createCaptureSessionByOutputConfigurations} has no effect.</p>
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800353 *
Emilian Peev03233152017-10-27 16:01:20 +0100354 * <p>Up to {@link #getMaxSharedSurfaceCount} surfaces can be shared for an OutputConfiguration.
355 * The supported surfaces for sharing must be of type SurfaceTexture, SurfaceView,
356 * MediaRecorder, MediaCodec, or implementation defined ImageReader.</p>
Shuzhen Wang9c663d42016-10-28 23:25:02 -0700357 */
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800358 public void enableSurfaceSharing() {
359 mIsShared = true;
Zhijun Hec8b181e2016-05-30 14:54:39 -0700360 }
361
362 /**
Shuzhen Wang23d29382017-11-26 17:24:56 -0800363 * Set the id of the physical camera for this OutputConfiguration
364 *
365 * <p>In the case one logical camera is made up of multiple physical cameras, it could be
366 * desirable for the camera application to request streams from individual physical cameras.
367 * This call achieves it by mapping the OutputConfiguration to the physical camera id.</p>
368 *
Shuzhen Wang2d5bbe4b2018-01-30 10:34:01 -0800369 * <p>The valid physical camera ids can be queried by {@link
Shuzhen Wang23d29382017-11-26 17:24:56 -0800370 * android.hardware.camera2.CameraCharacteristics#getPhysicalCameraIds}.
371 * </p>
372 *
373 * <p>Passing in a null physicalCameraId means that the OutputConfiguration is for a logical
374 * stream.</p>
375 *
376 * <p>This function must be called before {@link
377 * CameraDevice#createCaptureSessionByOutputConfigurations} or {@link
378 * CameraDevice#createReprocessableCaptureSessionByConfigurations}. Calling this function
379 * after {@link CameraDevice#createCaptureSessionByOutputConfigurations} or {@link
380 * CameraDevice#createReprocessableCaptureSessionByConfigurations} has no effect.</p>
381 *
382 * <p>The surface belonging to a physical camera OutputConfiguration must not be used as input
383 * or output of a reprocessing request. </p>
384 */
385 public void setPhysicalCameraId(@Nullable String physicalCameraId) {
386 mPhysicalCameraId = physicalCameraId;
387 }
388
389 /**
390 * Check if this configuration is for a physical camera.
391 *
392 * <p>This returns true if the output configuration was for a physical camera making up a
393 * logical multi camera via {@link OutputConfiguration#setPhysicalCameraId}.</p>
394 * @hide
395 */
396 public boolean isForPhysicalCamera() {
397 return (mPhysicalCameraId != null);
398 }
399
400 /**
Zhijun Hec8b181e2016-05-30 14:54:39 -0700401 * Check if this configuration has deferred configuration.
402 *
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800403 * <p>This will return true if the output configuration was constructed with surface deferred by
404 * {@link OutputConfiguration#OutputConfiguration(Size, Class)}. It will return true even after
405 * the deferred surface is added later by {@link OutputConfiguration#addSurface}.</p>
Zhijun Hec8b181e2016-05-30 14:54:39 -0700406 *
407 * @return true if this configuration has deferred surface.
408 * @hide
409 */
410 public boolean isDeferredConfiguration() {
411 return mIsDeferredConfig;
412 }
413
414 /**
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800415 * Add a surface to this OutputConfiguration.
Zhijun Hec8b181e2016-05-30 14:54:39 -0700416 *
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800417 * <p> This function can be called before or after {@link
418 * CameraDevice#createCaptureSessionByOutputConfigurations}. If it's called after,
419 * the application must finalize the capture session with
Emilian Peev03233152017-10-27 16:01:20 +0100420 * {@link CameraCaptureSession#finalizeOutputConfigurations}. It is possible to call this method
421 * after the output configurations have been finalized only in cases of enabled surface sharing
422 * see {@link #enableSurfaceSharing}. The modified output configuration must be updated with
423 * {@link CameraCaptureSession#updateOutputConfiguration}.</p>
Zhijun Hec8b181e2016-05-30 14:54:39 -0700424 *
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800425 * <p> If the OutputConfiguration was constructed with a deferred surface by {@link
426 * OutputConfiguration#OutputConfiguration(Size, Class)}, the added surface must be obtained
427 * from {@link android.view.SurfaceView} by calling {@link android.view.SurfaceHolder#getSurface},
428 * or from {@link android.graphics.SurfaceTexture} via
429 * {@link android.view.Surface#Surface(android.graphics.SurfaceTexture)}).</p>
430 *
431 * <p> If the OutputConfiguration was constructed by other constructors, the added
432 * surface must be compatible with the existing surface. See {@link #enableSurfaceSharing} for
433 * details of compatible surfaces.</p>
434 *
435 * <p> If the OutputConfiguration already contains a Surface, {@link #enableSurfaceSharing} must
436 * be called before calling this function to add a new Surface.</p>
437 *
438 * @param surface The surface to be added.
439 * @throws IllegalArgumentException if the Surface is invalid, the Surface's
Shuzhen Wang21d63b22017-01-27 22:32:26 -0800440 * dataspace/format doesn't match, or adding the Surface would exceed number of
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800441 * shared surfaces supported.
442 * @throws IllegalStateException if the Surface was already added to this OutputConfiguration,
443 * or if the OutputConfiguration is not shared and it already has a surface associated
444 * with it.
Zhijun Hec8b181e2016-05-30 14:54:39 -0700445 */
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800446 public void addSurface(@NonNull Surface surface) {
Zhijun Hec8b181e2016-05-30 14:54:39 -0700447 checkNotNull(surface, "Surface must not be null");
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800448 if (mSurfaces.contains(surface)) {
449 throw new IllegalStateException("Surface is already added!");
450 }
451 if (mSurfaces.size() == 1 && !mIsShared) {
452 throw new IllegalStateException("Cannot have 2 surfaces for a non-sharing configuration");
453 }
454 if (mSurfaces.size() + 1 > MAX_SURFACES_COUNT) {
455 throw new IllegalArgumentException("Exceeds maximum number of surfaces");
Zhijun Hec8b181e2016-05-30 14:54:39 -0700456 }
457
Shuzhen Wang21d63b22017-01-27 22:32:26 -0800458 // This will throw IAE is the surface was abandoned.
459 Size surfaceSize = SurfaceUtils.getSurfaceSize(surface);
460 if (!surfaceSize.equals(mConfiguredSize)) {
461 Log.w(TAG, "Added surface size " + surfaceSize +
462 " is different than pre-configured size " + mConfiguredSize +
463 ", the pre-configured size will be used.");
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800464 }
Shuzhen Wang21d63b22017-01-27 22:32:26 -0800465
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800466 if (mConfiguredFormat != SurfaceUtils.getSurfaceFormat(surface)) {
467 throw new IllegalArgumentException("The format of added surface format doesn't match");
Zhijun Hec8b181e2016-05-30 14:54:39 -0700468 }
469
Shuzhen Wang75d66022017-02-21 10:47:45 -0800470 // If the surface format is PRIVATE, do not enforce dataSpace because camera device may
471 // override it.
472 if (mConfiguredFormat != ImageFormat.PRIVATE &&
473 mConfiguredDataspace != SurfaceUtils.getSurfaceDataspace(surface)) {
474 throw new IllegalArgumentException("The dataspace of added surface doesn't match");
475 }
476
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800477 mSurfaces.add(surface);
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700478 }
479
480 /**
Emilian Peev03233152017-10-27 16:01:20 +0100481 * Remove a surface from this OutputConfiguration.
482 *
483 * <p> Surfaces added via calls to {@link #addSurface} can also be removed from the
484 * OutputConfiguration. The only notable exception is the surface associated with
485 * the OutputConfigration see {@link #getSurface} which was passed as part of the constructor
486 * or was added first in the deferred case
487 * {@link OutputConfiguration#OutputConfiguration(Size, Class)}.</p>
488 *
489 * @param surface The surface to be removed.
490 *
491 * @throws IllegalArgumentException If the surface is associated with this OutputConfiguration
492 * (see {@link #getSurface}) or the surface didn't get added
493 * with {@link #addSurface}.
494 */
495 public void removeSurface(@NonNull Surface surface) {
496 if (getSurface() == surface) {
497 throw new IllegalArgumentException(
498 "Cannot remove surface associated with this output configuration");
499 }
500 if (!mSurfaces.remove(surface)) {
501 throw new IllegalArgumentException("Surface is not part of this output configuration");
502 }
503 }
504
505 /**
Zhijun He445b3162016-01-18 15:34:28 -0800506 * Create a new {@link OutputConfiguration} instance with another {@link OutputConfiguration}
507 * instance.
508 *
509 * @param other Another {@link OutputConfiguration} instance to be copied.
510 *
511 * @hide
512 */
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700513 public OutputConfiguration(@NonNull OutputConfiguration other) {
Zhijun He445b3162016-01-18 15:34:28 -0800514 if (other == null) {
515 throw new IllegalArgumentException("OutputConfiguration shouldn't be null");
516 }
517
Shuzhen Wang9c663d42016-10-28 23:25:02 -0700518 this.mSurfaces = other.mSurfaces;
Zhijun He445b3162016-01-18 15:34:28 -0800519 this.mRotation = other.mRotation;
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700520 this.mSurfaceGroupId = other.mSurfaceGroupId;
Zhijun Hec8b181e2016-05-30 14:54:39 -0700521 this.mSurfaceType = other.mSurfaceType;
Zhijun He445b3162016-01-18 15:34:28 -0800522 this.mConfiguredDataspace = other.mConfiguredDataspace;
523 this.mConfiguredFormat = other.mConfiguredFormat;
524 this.mConfiguredSize = other.mConfiguredSize;
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700525 this.mConfiguredGenerationId = other.mConfiguredGenerationId;
Zhijun Hec8b181e2016-05-30 14:54:39 -0700526 this.mIsDeferredConfig = other.mIsDeferredConfig;
Shuzhen Wangb4d0fa3d32017-12-08 12:16:49 -0800527 this.mIsShared = other.mIsShared;
Shuzhen Wang23d29382017-11-26 17:24:56 -0800528 this.mPhysicalCameraId = other.mPhysicalCameraId;
Zhijun He445b3162016-01-18 15:34:28 -0800529 }
530
531 /**
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700532 * Create an OutputConfiguration from Parcel.
533 */
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700534 private OutputConfiguration(@NonNull Parcel source) {
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700535 int rotation = source.readInt();
Zhijun He445b3162016-01-18 15:34:28 -0800536 int surfaceSetId = source.readInt();
Zhijun Hec8b181e2016-05-30 14:54:39 -0700537 int surfaceType = source.readInt();
538 int width = source.readInt();
539 int height = source.readInt();
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800540 boolean isDeferred = source.readInt() == 1;
Shuzhen Wangb4d0fa3d32017-12-08 12:16:49 -0800541 boolean isShared = source.readInt() == 1;
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800542 ArrayList<Surface> surfaces = new ArrayList<Surface>();
543 source.readTypedList(surfaces, Surface.CREATOR);
Shuzhen Wang23d29382017-11-26 17:24:56 -0800544 String physicalCameraId = source.readString();
Shuzhen Wang9c663d42016-10-28 23:25:02 -0700545
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700546 checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
Shuzhen Wang9c663d42016-10-28 23:25:02 -0700547
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700548 mSurfaceGroupId = surfaceSetId;
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700549 mRotation = rotation;
Shuzhen Wang9c663d42016-10-28 23:25:02 -0700550 mSurfaces = surfaces;
551 mConfiguredSize = new Size(width, height);
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800552 mIsDeferredConfig = isDeferred;
Shuzhen Wangb4d0fa3d32017-12-08 12:16:49 -0800553 mIsShared = isShared;
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800554 mSurfaces = surfaces;
555 if (mSurfaces.size() > 0) {
Zhijun Hec8b181e2016-05-30 14:54:39 -0700556 mSurfaceType = SURFACE_TYPE_UNKNOWN;
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800557 mConfiguredFormat = SurfaceUtils.getSurfaceFormat(mSurfaces.get(0));
558 mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(mSurfaces.get(0));
559 mConfiguredGenerationId = mSurfaces.get(0).getGenerationId();
Zhijun Hec8b181e2016-05-30 14:54:39 -0700560 } else {
561 mSurfaceType = surfaceType;
Zhijun Hec8b181e2016-05-30 14:54:39 -0700562 mConfiguredFormat = StreamConfigurationMap.imageFormatToInternal(ImageFormat.PRIVATE);
Zhijun Hec8b181e2016-05-30 14:54:39 -0700563 mConfiguredDataspace =
564 StreamConfigurationMap.imageFormatToDataspace(ImageFormat.PRIVATE);
Shuzhen Wang9c663d42016-10-28 23:25:02 -0700565 mConfiguredGenerationId = 0;
566 }
Shuzhen Wang23d29382017-11-26 17:24:56 -0800567 mPhysicalCameraId = physicalCameraId;
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700568 }
569
570 /**
Emilian Peev03233152017-10-27 16:01:20 +0100571 * Get the maximum supported shared {@link Surface} count.
572 *
573 * @return the maximum number of surfaces that can be added per each OutputConfiguration.
574 *
575 * @see #enableSurfaceSharing
576 */
Emilian Peev31c11a02018-01-29 16:41:57 +0000577 public int getMaxSharedSurfaceCount() {
Emilian Peev03233152017-10-27 16:01:20 +0100578 return MAX_SURFACES_COUNT;
579 }
580
581 /**
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700582 * Get the {@link Surface} associated with this {@link OutputConfiguration}.
583 *
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800584 * If more than one surface is associated with this {@link OutputConfiguration}, return the
585 * first one as specified in the constructor or {@link OutputConfiguration#addSurface}.
Shuzhen Wang9c663d42016-10-28 23:25:02 -0700586 */
587 public @Nullable Surface getSurface() {
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800588 if (mSurfaces.size() == 0) {
589 return null;
590 }
591
592 return mSurfaces.get(0);
Shuzhen Wang9c663d42016-10-28 23:25:02 -0700593 }
594
595 /**
596 * Get the immutable list of surfaces associated with this {@link OutputConfiguration}.
597 *
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800598 * @return the list of surfaces associated with this {@link OutputConfiguration} as specified in
599 * the constructor and {@link OutputConfiguration#addSurface}. The list should not be modified.
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700600 */
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700601 @NonNull
Shuzhen Wang9c663d42016-10-28 23:25:02 -0700602 public List<Surface> getSurfaces() {
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800603 return Collections.unmodifiableList(mSurfaces);
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700604 }
605
606 /**
607 * Get the rotation associated with this {@link OutputConfiguration}.
608 *
609 * @return the rotation associated with this {@link OutputConfiguration}.
610 * Value will be one of ROTATION_[0, 90, 180, 270]
Zhijun He445b3162016-01-18 15:34:28 -0800611 *
612 * @hide
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700613 */
Zhijun He445b3162016-01-18 15:34:28 -0800614 @SystemApi
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700615 public int getRotation() {
616 return mRotation;
617 }
618
Zhijun He445b3162016-01-18 15:34:28 -0800619 /**
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700620 * Get the surface group ID associated with this {@link OutputConfiguration}.
Zhijun He445b3162016-01-18 15:34:28 -0800621 *
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700622 * @return the surface group ID associated with this {@link OutputConfiguration}.
623 * The default value is {@value #SURFACE_GROUP_ID_NONE}.
Zhijun He445b3162016-01-18 15:34:28 -0800624 */
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700625 public int getSurfaceGroupId() {
626 return mSurfaceGroupId;
Zhijun He445b3162016-01-18 15:34:28 -0800627 }
628
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700629 public static final Parcelable.Creator<OutputConfiguration> CREATOR =
630 new Parcelable.Creator<OutputConfiguration>() {
631 @Override
632 public OutputConfiguration createFromParcel(Parcel source) {
633 try {
634 OutputConfiguration outputConfiguration = new OutputConfiguration(source);
635 return outputConfiguration;
636 } catch (Exception e) {
637 Log.e(TAG, "Exception creating OutputConfiguration from parcel", e);
638 return null;
639 }
640 }
641
642 @Override
643 public OutputConfiguration[] newArray(int size) {
644 return new OutputConfiguration[size];
645 }
646 };
647
648 @Override
649 public int describeContents() {
650 return 0;
651 }
652
653 @Override
654 public void writeToParcel(Parcel dest, int flags) {
655 if (dest == null) {
656 throw new IllegalArgumentException("dest must not be null");
657 }
658 dest.writeInt(mRotation);
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700659 dest.writeInt(mSurfaceGroupId);
Zhijun Hec8b181e2016-05-30 14:54:39 -0700660 dest.writeInt(mSurfaceType);
661 dest.writeInt(mConfiguredSize.getWidth());
662 dest.writeInt(mConfiguredSize.getHeight());
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800663 dest.writeInt(mIsDeferredConfig ? 1 : 0);
664 dest.writeInt(mIsShared ? 1 : 0);
665 dest.writeTypedList(mSurfaces);
Shuzhen Wang23d29382017-11-26 17:24:56 -0800666 dest.writeString(mPhysicalCameraId);
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700667 }
668
Yin-Chia Yeh61f15362015-04-03 10:46:25 -0700669 /**
670 * Check if this {@link OutputConfiguration} is equal to another {@link OutputConfiguration}.
671 *
Chien-Yu Chen828adbb2015-08-18 12:46:39 -0700672 * <p>Two output configurations are only equal if and only if the underlying surfaces, surface
673 * properties (width, height, format, dataspace) when the output configurations are created,
674 * and all other configuration parameters are equal. </p>
Yin-Chia Yeh61f15362015-04-03 10:46:25 -0700675 *
676 * @return {@code true} if the objects were equal, {@code false} otherwise
677 */
678 @Override
679 public boolean equals(Object obj) {
680 if (obj == null) {
681 return false;
682 } else if (this == obj) {
683 return true;
684 } else if (obj instanceof OutputConfiguration) {
685 final OutputConfiguration other = (OutputConfiguration) obj;
Shuzhen Wang9c663d42016-10-28 23:25:02 -0700686 if (mRotation != other.mRotation ||
687 !mConfiguredSize.equals(other.mConfiguredSize) ||
688 mConfiguredFormat != other.mConfiguredFormat ||
689 mSurfaceGroupId != other.mSurfaceGroupId ||
690 mSurfaceType != other.mSurfaceType ||
691 mIsDeferredConfig != other.mIsDeferredConfig ||
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800692 mIsShared != other.mIsShared ||
Shuzhen Wang9c663d42016-10-28 23:25:02 -0700693 mConfiguredFormat != other.mConfiguredFormat ||
694 mConfiguredDataspace != other.mConfiguredDataspace ||
Shuzhen Wang9c663d42016-10-28 23:25:02 -0700695 mConfiguredGenerationId != other.mConfiguredGenerationId)
696 return false;
697
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800698 int minLen = Math.min(mSurfaces.size(), other.mSurfaces.size());
699 for (int i = 0; i < minLen; i++) {
700 if (mSurfaces.get(i) != other.mSurfaces.get(i))
Shuzhen Wang9c663d42016-10-28 23:25:02 -0700701 return false;
Zhijun Hec8b181e2016-05-30 14:54:39 -0700702 }
Shuzhen Wang9c663d42016-10-28 23:25:02 -0700703
704 return true;
Yin-Chia Yeh61f15362015-04-03 10:46:25 -0700705 }
706 return false;
707 }
708
709 /**
710 * {@inheritDoc}
711 */
712 @Override
713 public int hashCode() {
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800714 // Need ensure that the hashcode remains unchanged after adding a deferred surface. Otherwise
Shuzhen Wang9c663d42016-10-28 23:25:02 -0700715 // the deferred output configuration will be lost in the camera streammap after the deferred
Zhijun Hec8b181e2016-05-30 14:54:39 -0700716 // surface is set.
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800717 if (mIsDeferredConfig) {
718 return HashCodeHelpers.hashCode(
719 mRotation, mConfiguredSize.hashCode(), mConfiguredFormat, mConfiguredDataspace,
Shuzhen Wang23d29382017-11-26 17:24:56 -0800720 mSurfaceGroupId, mSurfaceType, mIsShared ? 1 : 0,
721 mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode());
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800722 }
Zhijun Hec8b181e2016-05-30 14:54:39 -0700723
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700724 return HashCodeHelpers.hashCode(
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800725 mRotation, mSurfaces.hashCode(), mConfiguredGenerationId,
Shuzhen Wang9c663d42016-10-28 23:25:02 -0700726 mConfiguredSize.hashCode(), mConfiguredFormat,
Shuzhen Wang23d29382017-11-26 17:24:56 -0800727 mConfiguredDataspace, mSurfaceGroupId, mIsShared ? 1 : 0,
728 mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode());
Yin-Chia Yeh61f15362015-04-03 10:46:25 -0700729 }
730
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700731 private static final String TAG = "OutputConfiguration";
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800732 private ArrayList<Surface> mSurfaces;
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700733 private final int mRotation;
Zhijun Hec8b181e2016-05-30 14:54:39 -0700734 private final int mSurfaceGroupId;
735 // Surface source type, this is only used by the deferred surface configuration objects.
736 private final int mSurfaceType;
Chien-Yu Chen828adbb2015-08-18 12:46:39 -0700737
738 // The size, format, and dataspace of the surface when OutputConfiguration is created.
739 private final Size mConfiguredSize;
740 private final int mConfiguredFormat;
741 private final int mConfiguredDataspace;
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700742 // Surface generation ID to distinguish changes to Surface native internals
743 private final int mConfiguredGenerationId;
Zhijun Hec8b181e2016-05-30 14:54:39 -0700744 // Flag indicating if this config has deferred surface.
745 private final boolean mIsDeferredConfig;
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800746 // Flag indicating if this config has shared surfaces
747 private boolean mIsShared;
Shuzhen Wang23d29382017-11-26 17:24:56 -0800748 // The physical camera id that this output configuration is for.
749 private String mPhysicalCameraId;
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700750}