• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
18 package android.hardware.camera2.params;
19 
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.SystemApi;
23 import android.hardware.camera2.CameraDevice;
24 import android.hardware.camera2.utils.HashCodeHelpers;
25 import android.hardware.camera2.utils.SurfaceUtils;
26 import android.os.Parcel;
27 import android.os.Parcelable;
28 import android.util.Log;
29 import android.util.Size;
30 import android.view.Surface;
31 
32 import static com.android.internal.util.Preconditions.*;
33 
34 /**
35  * A class for describing camera output, which contains a {@link Surface} and its specific
36  * configuration for creating capture session.
37  *
38  * @see CameraDevice#createCaptureSessionByOutputConfiguration
39  *
40  */
41 public final class OutputConfiguration implements Parcelable {
42 
43     /**
44      * Rotation constant: 0 degree rotation (no rotation)
45      *
46      * @hide
47      */
48     @SystemApi
49     public static final int ROTATION_0 = 0;
50 
51     /**
52      * Rotation constant: 90 degree counterclockwise rotation.
53      *
54      * @hide
55      */
56     @SystemApi
57     public static final int ROTATION_90 = 1;
58 
59     /**
60      * Rotation constant: 180 degree counterclockwise rotation.
61      *
62      * @hide
63      */
64     @SystemApi
65     public static final int ROTATION_180 = 2;
66 
67     /**
68      * Rotation constant: 270 degree counterclockwise rotation.
69      *
70      * @hide
71      */
72     @SystemApi
73     public static final int ROTATION_270 = 3;
74 
75     /**
76      * Invalid surface group ID.
77      *
78      *<p>An {@link OutputConfiguration} with this value indicates that the included surface
79      *doesn't belong to any surface group.</p>
80      */
81     public static final int SURFACE_GROUP_ID_NONE = -1;
82 
83     /**
84      * Create a new {@link OutputConfiguration} instance with a {@link Surface}.
85      *
86      * @param surface
87      *          A Surface for camera to output to.
88      *
89      * <p>This constructor creates a default configuration, with a surface group ID of
90      * {@value #SURFACE_GROUP_ID_NONE}.</p>
91      *
92      */
OutputConfiguration(@onNull Surface surface)93     public OutputConfiguration(@NonNull Surface surface) {
94         this(SURFACE_GROUP_ID_NONE, surface, ROTATION_0);
95     }
96 
97     /**
98      * Create a new {@link OutputConfiguration} instance with a {@link Surface},
99      * with a surface group ID.
100      *
101      * <p>
102      * A surface group ID is used to identify which surface group this output surface belongs to. A
103      * surface group is a group of output surfaces that are not intended to receive camera output
104      * buffer streams simultaneously. The {@link CameraDevice} may be able to share the buffers used
105      * by all the surfaces from the same surface group, therefore may reduce the overall memory
106      * footprint. The application should only set the same set ID for the streams that are not
107      * simultaneously streaming. A negative ID indicates that this surface doesn't belong to any
108      * surface group. The default value is {@value #SURFACE_GROUP_ID_NONE}.</p>
109      *
110      * <p>For example, a video chat application that has an adaptive output resolution feature would
111      * need two (or more) output resolutions, to switch resolutions without any output glitches.
112      * However, at any given time, only one output is active to minimize outgoing network bandwidth
113      * and encoding overhead.  To save memory, the application should set the video outputs to have
114      * the same non-negative group ID, so that the camera device can share the same memory region
115      * for the alternating outputs.</p>
116      *
117      * <p>It is not an error to include output streams with the same group ID in the same capture
118      * request, but the resulting memory consumption may be higher than if the two streams were
119      * not in the same surface group to begin with, especially if the outputs have substantially
120      * different dimensions.</p>
121      *
122      * @param surfaceGroupId
123      *          A group ID for this output, used for sharing memory between multiple outputs.
124      * @param surface
125      *          A Surface for camera to output to.
126      *
127      */
OutputConfiguration(int surfaceGroupId, @NonNull Surface surface)128     public OutputConfiguration(int surfaceGroupId, @NonNull Surface surface) {
129         this(surfaceGroupId, surface, ROTATION_0);
130     }
131 
132     /**
133      * Create a new {@link OutputConfiguration} instance.
134      *
135      * <p>This constructor takes an argument for desired camera rotation</p>
136      *
137      * @param surface
138      *          A Surface for camera to output to.
139      * @param rotation
140      *          The desired rotation to be applied on camera output. Value must be one of
141      *          ROTATION_[0, 90, 180, 270]. Note that when the rotation is 90 or 270 degrees,
142      *          application should make sure corresponding surface size has width and height
143      *          transposed relative to the width and height without rotation. For example,
144      *          if application needs camera to capture 1280x720 picture and rotate it by 90 degree,
145      *          application should set rotation to {@code ROTATION_90} and make sure the
146      *          corresponding Surface size is 720x1280. Note that {@link CameraDevice} might
147      *          throw {@code IllegalArgumentException} if device cannot perform such rotation.
148      * @hide
149      */
150     @SystemApi
OutputConfiguration(@onNull Surface surface, int rotation)151     public OutputConfiguration(@NonNull Surface surface, int rotation) {
152         this(SURFACE_GROUP_ID_NONE, surface, rotation);
153     }
154 
155 
156     /**
157      * Create a new {@link OutputConfiguration} instance, with rotation and a group ID.
158      *
159      * <p>This constructor takes an argument for desired camera rotation and for the surface group
160      * ID.  See {@link #OutputConfiguration(int, Surface)} for details of the group ID.</p>
161      *
162      * @param surfaceGroupId
163      *          A group ID for this output, used for sharing memory between multiple outputs.
164      * @param surface
165      *          A Surface for camera to output to.
166      * @param rotation
167      *          The desired rotation to be applied on camera output. Value must be one of
168      *          ROTATION_[0, 90, 180, 270]. Note that when the rotation is 90 or 270 degrees,
169      *          application should make sure corresponding surface size has width and height
170      *          transposed relative to the width and height without rotation. For example,
171      *          if application needs camera to capture 1280x720 picture and rotate it by 90 degree,
172      *          application should set rotation to {@code ROTATION_90} and make sure the
173      *          corresponding Surface size is 720x1280. Note that {@link CameraDevice} might
174      *          throw {@code IllegalArgumentException} if device cannot perform such rotation.
175      * @hide
176      */
177     @SystemApi
OutputConfiguration(int surfaceGroupId, @NonNull Surface surface, int rotation)178     public OutputConfiguration(int surfaceGroupId, @NonNull Surface surface, int rotation) {
179         checkNotNull(surface, "Surface must not be null");
180         checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
181         mSurfaceGroupId = surfaceGroupId;
182         mSurface = surface;
183         mRotation = rotation;
184         mConfiguredSize = SurfaceUtils.getSurfaceSize(surface);
185         mConfiguredFormat = SurfaceUtils.getSurfaceFormat(surface);
186         mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(surface);
187         mConfiguredGenerationId = surface.getGenerationId();
188     }
189 
190     /**
191      * Create a new {@link OutputConfiguration} instance with another {@link OutputConfiguration}
192      * instance.
193      *
194      * @param other Another {@link OutputConfiguration} instance to be copied.
195      *
196      * @hide
197      */
OutputConfiguration(@onNull OutputConfiguration other)198     public OutputConfiguration(@NonNull OutputConfiguration other) {
199         if (other == null) {
200             throw new IllegalArgumentException("OutputConfiguration shouldn't be null");
201         }
202 
203         this.mSurface = other.mSurface;
204         this.mRotation = other.mRotation;
205         this.mSurfaceGroupId = other.mSurfaceGroupId;
206         this.mConfiguredDataspace = other.mConfiguredDataspace;
207         this.mConfiguredFormat = other.mConfiguredFormat;
208         this.mConfiguredSize = other.mConfiguredSize;
209         this.mConfiguredGenerationId = other.mConfiguredGenerationId;
210     }
211 
212     /**
213      * Create an OutputConfiguration from Parcel.
214      */
OutputConfiguration(@onNull Parcel source)215     private OutputConfiguration(@NonNull Parcel source) {
216         int rotation = source.readInt();
217         int surfaceSetId = source.readInt();
218         Surface surface = Surface.CREATOR.createFromParcel(source);
219         checkNotNull(surface, "Surface must not be null");
220         checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
221         mSurfaceGroupId = surfaceSetId;
222         mSurface = surface;
223         mRotation = rotation;
224         mConfiguredSize = SurfaceUtils.getSurfaceSize(mSurface);
225         mConfiguredFormat = SurfaceUtils.getSurfaceFormat(mSurface);
226         mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(mSurface);
227         mConfiguredGenerationId = mSurface.getGenerationId();
228     }
229 
230     /**
231      * Get the {@link Surface} associated with this {@link OutputConfiguration}.
232      *
233      * @return the {@link Surface} associated with this {@link OutputConfiguration}.
234      */
235     @NonNull
getSurface()236     public Surface getSurface() {
237         return mSurface;
238     }
239 
240     /**
241      * Get the rotation associated with this {@link OutputConfiguration}.
242      *
243      * @return the rotation associated with this {@link OutputConfiguration}.
244      *         Value will be one of ROTATION_[0, 90, 180, 270]
245      *
246      * @hide
247      */
248     @SystemApi
getRotation()249     public int getRotation() {
250         return mRotation;
251     }
252 
253     /**
254      * Get the surface group ID associated with this {@link OutputConfiguration}.
255      *
256      * @return the surface group ID associated with this {@link OutputConfiguration}.
257      *         The default value is {@value #SURFACE_GROUP_ID_NONE}.
258      */
getSurfaceGroupId()259     public int getSurfaceGroupId() {
260         return mSurfaceGroupId;
261     }
262 
263     public static final Parcelable.Creator<OutputConfiguration> CREATOR =
264             new Parcelable.Creator<OutputConfiguration>() {
265         @Override
266         public OutputConfiguration createFromParcel(Parcel source) {
267             try {
268                 OutputConfiguration outputConfiguration = new OutputConfiguration(source);
269                 return outputConfiguration;
270             } catch (Exception e) {
271                 Log.e(TAG, "Exception creating OutputConfiguration from parcel", e);
272                 return null;
273             }
274         }
275 
276         @Override
277         public OutputConfiguration[] newArray(int size) {
278             return new OutputConfiguration[size];
279         }
280     };
281 
282     @Override
describeContents()283     public int describeContents() {
284         return 0;
285     }
286 
287     @Override
writeToParcel(Parcel dest, int flags)288     public void writeToParcel(Parcel dest, int flags) {
289         if (dest == null) {
290             throw new IllegalArgumentException("dest must not be null");
291         }
292         dest.writeInt(mRotation);
293         dest.writeInt(mSurfaceGroupId);
294         mSurface.writeToParcel(dest, flags);
295     }
296 
297     /**
298      * Check if this {@link OutputConfiguration} is equal to another {@link OutputConfiguration}.
299      *
300      * <p>Two output configurations are only equal if and only if the underlying surfaces, surface
301      * properties (width, height, format, dataspace) when the output configurations are created,
302      * and all other configuration parameters are equal. </p>
303      *
304      * @return {@code true} if the objects were equal, {@code false} otherwise
305      */
306     @Override
equals(Object obj)307     public boolean equals(Object obj) {
308         if (obj == null) {
309             return false;
310         } else if (this == obj) {
311             return true;
312         } else if (obj instanceof OutputConfiguration) {
313             final OutputConfiguration other = (OutputConfiguration) obj;
314             return mRotation == other.mRotation &&
315                    mSurface == other.mSurface &&
316                    mConfiguredGenerationId == other.mConfiguredGenerationId &&
317                    mConfiguredSize.equals(other.mConfiguredSize) &&
318                    mConfiguredFormat == other.mConfiguredFormat &&
319                    mConfiguredDataspace == other.mConfiguredDataspace &&
320                    mSurfaceGroupId == other.mSurfaceGroupId;
321         }
322         return false;
323     }
324 
325     /**
326      * {@inheritDoc}
327      */
328     @Override
hashCode()329     public int hashCode() {
330         return HashCodeHelpers.hashCode(
331             mRotation, mSurface.hashCode(), mConfiguredGenerationId,
332             mConfiguredSize.hashCode(), mConfiguredFormat, mConfiguredDataspace, mSurfaceGroupId);
333     }
334 
335     private static final String TAG = "OutputConfiguration";
336     private final Surface mSurface;
337     private final int mRotation;
338     private int mSurfaceGroupId;
339 
340     // The size, format, and dataspace of the surface when OutputConfiguration is created.
341     private final Size mConfiguredSize;
342     private final int mConfiguredFormat;
343     private final int mConfiguredDataspace;
344     // Surface generation ID to distinguish changes to Surface native internals
345     private final int mConfiguredGenerationId;
346 }
347