1 /*
2  * Copyright (C) 2017 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 static com.android.internal.util.Preconditions.*;
21 
22 import android.annotation.CallbackExecutor;
23 import android.annotation.IntDef;
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.annotation.SuppressLint;
27 import android.graphics.ColorSpace;
28 import android.hardware.camera2.CameraCaptureSession;
29 import android.hardware.camera2.CameraCharacteristics;
30 import android.hardware.camera2.CameraDevice;
31 import android.hardware.camera2.CaptureRequest;
32 import android.hardware.camera2.params.InputConfiguration;
33 import android.hardware.camera2.params.OutputConfiguration;
34 import android.hardware.camera2.utils.HashCodeHelpers;
35 import android.media.ImageReader;
36 import android.os.Parcel;
37 import android.os.Parcelable;
38 import android.util.Log;
39 
40 import java.lang.annotation.Retention;
41 import java.lang.annotation.RetentionPolicy;
42 import java.util.ArrayList;
43 import java.util.Collections;
44 import java.util.List;
45 import java.util.concurrent.Executor;
46 
47 /**
48  * A helper class that aggregates all supported arguments for capture session initialization.
49  */
50 public final class SessionConfiguration implements Parcelable {
51     private static final String TAG = "SessionConfiguration";
52 
53     /**
54      * A regular session type containing instances of {@link OutputConfiguration} running
55      * at regular non high speed FPS ranges and optionally {@link InputConfiguration} for
56      * reprocessable sessions.
57      *
58      * @see CameraDevice#createCaptureSession(SessionConfiguration)
59      * @see CameraDevice#createReprocessableCaptureSession
60      */
61     public static final int SESSION_REGULAR = CameraDevice.SESSION_OPERATION_MODE_NORMAL;
62 
63     /**
64      * A high speed session type that can only contain instances of {@link OutputConfiguration}.
65      * The outputs can run using high speed FPS ranges. Calls to {@link #setInputConfiguration}
66      * are not supported.
67      * <p>
68      * When using this type, the CameraCaptureSession returned by
69      * {@link android.hardware.camera2.CameraCaptureSession.StateCallback} can be cast to a
70      * {@link android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession} to access the extra
71      * methods for constrained high speed recording.
72      * </p>
73      *
74      * @see CameraDevice#createConstrainedHighSpeedCaptureSession
75      */
76     public static final int SESSION_HIGH_SPEED =
77         CameraDevice.SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED;
78 
79     /**
80      * First vendor-specific session mode
81      * @hide
82      */
83     public static final int SESSION_VENDOR_START =
84         CameraDevice.SESSION_OPERATION_MODE_VENDOR_START;
85 
86      /** @hide */
87     @Retention(RetentionPolicy.SOURCE)
88     @IntDef(prefix = {"SESSION_"}, value =
89             {SESSION_REGULAR,
90              SESSION_HIGH_SPEED })
91     public @interface SessionMode {};
92 
93     // Camera capture session related parameters.
94     private List<OutputConfiguration> mOutputConfigurations;
95     private CameraCaptureSession.StateCallback mStateCallback;
96     private int mSessionType;
97     private Executor mExecutor = null;
98     private InputConfiguration mInputConfig = null;
99     private CaptureRequest mSessionParameters = null;
100     private int mColorSpace;
101 
102     /**
103      * Create a new {@link SessionConfiguration}.
104      *
105      * @param sessionType The session type.
106      * @param outputs A list of output configurations for the capture session.
107      * @param executor The executor which should be used to invoke the callback. In general it is
108      *                 recommended that camera operations are not done on the main (UI) thread.
109      * @param cb A state callback interface implementation.
110      *
111      * @see #SESSION_REGULAR
112      * @see #SESSION_HIGH_SPEED
113      * @see CameraDevice#createCaptureSession(SessionConfiguration)
114      */
SessionConfiguration(@essionMode int sessionType, @NonNull List<OutputConfiguration> outputs, @NonNull @CallbackExecutor Executor executor, @NonNull CameraCaptureSession.StateCallback cb)115     public SessionConfiguration(@SessionMode int sessionType,
116             @NonNull List<OutputConfiguration> outputs,
117             @NonNull @CallbackExecutor Executor executor,
118             @NonNull CameraCaptureSession.StateCallback cb) {
119         mSessionType = sessionType;
120         mOutputConfigurations = Collections.unmodifiableList(new ArrayList<>(outputs));
121         mStateCallback = cb;
122         mExecutor = executor;
123     }
124 
125     /**
126      * Create a SessionConfiguration from Parcel.
127      * No support for parcelable 'mStateCallback', 'mExecutor' and 'mSessionParameters' yet.
128      */
SessionConfiguration(@onNull Parcel source)129     private SessionConfiguration(@NonNull Parcel source) {
130         int sessionType = source.readInt();
131         int inputWidth = source.readInt();
132         int inputHeight = source.readInt();
133         int inputFormat = source.readInt();
134         boolean isInputMultiResolution = source.readBoolean();
135         ArrayList<OutputConfiguration> outConfigs = new ArrayList<OutputConfiguration>();
136         source.readTypedList(outConfigs, OutputConfiguration.CREATOR);
137 
138         if ((inputWidth > 0) && (inputHeight > 0) && (inputFormat != -1)) {
139             mInputConfig = new InputConfiguration(inputWidth, inputHeight,
140                     inputFormat, isInputMultiResolution);
141         }
142         mSessionType = sessionType;
143         mOutputConfigurations = outConfigs;
144     }
145 
146     public static final @android.annotation.NonNull Parcelable.Creator<SessionConfiguration> CREATOR =
147             new Parcelable.Creator<SessionConfiguration> () {
148         @Override
149         public SessionConfiguration createFromParcel(Parcel source) {
150             return new SessionConfiguration(source);
151         }
152 
153         @Override
154         public SessionConfiguration[] newArray(int size) {
155             return new SessionConfiguration[size];
156         }
157     };
158 
159     @Override
writeToParcel(Parcel dest, int flags)160     public void writeToParcel(Parcel dest, int flags) {
161         if (dest == null) {
162             throw new IllegalArgumentException("dest must not be null");
163         }
164         dest.writeInt(mSessionType);
165         if (mInputConfig != null) {
166             dest.writeInt(mInputConfig.getWidth());
167             dest.writeInt(mInputConfig.getHeight());
168             dest.writeInt(mInputConfig.getFormat());
169             dest.writeBoolean(mInputConfig.isMultiResolution());
170         } else {
171             dest.writeInt(/*inputWidth*/ 0);
172             dest.writeInt(/*inputHeight*/ 0);
173             dest.writeInt(/*inputFormat*/ -1);
174             dest.writeBoolean(/*isMultiResolution*/ false);
175         }
176         dest.writeTypedList(mOutputConfigurations);
177     }
178 
179     @Override
describeContents()180     public int describeContents() {
181         return 0;
182     }
183 
184     /**
185      * Check if this {@link SessionConfiguration} is equal to another {@link SessionConfiguration}.
186      *
187      * <p>Two output session configurations are only equal if and only if the underlying input
188      * configuration, output configurations, and session type are equal. </p>
189      *
190      * @return {@code true} if the objects were equal, {@code false} otherwise
191      */
192     @Override
equals(@ullable Object obj)193     public boolean equals(@Nullable Object obj) {
194         if (obj == null) {
195             return false;
196         } else if (this == obj) {
197             return true;
198         } else if (obj instanceof SessionConfiguration) {
199             final SessionConfiguration other = (SessionConfiguration) obj;
200             if (mInputConfig != other.mInputConfig || mSessionType != other.mSessionType ||
201                     mOutputConfigurations.size() != other.mOutputConfigurations.size()) {
202                 return false;
203             }
204 
205             for (int i = 0;  i < mOutputConfigurations.size(); i++) {
206                 if (!mOutputConfigurations.get(i).equals(other.mOutputConfigurations.get(i)))
207                     return false;
208             }
209 
210             return true;
211         }
212 
213         return false;
214     }
215 
216     /**
217      * {@inheritDoc}
218      */
219     @Override
hashCode()220     public int hashCode() {
221         return HashCodeHelpers.hashCode(mOutputConfigurations.hashCode(), mInputConfig.hashCode(),
222                 mSessionType);
223     }
224 
225     /**
226      * Retrieve the type of the capture session.
227      *
228      * @return The capture session type.
229      */
getSessionType()230     public @SessionMode int getSessionType() {
231         return mSessionType;
232     }
233 
234     /**
235      * Retrieve the {@link OutputConfiguration} list for the capture session.
236      *
237      * @return A list of output configurations for the capture session.
238      */
getOutputConfigurations()239     public List<OutputConfiguration> getOutputConfigurations() {
240         return mOutputConfigurations;
241     }
242 
243     /**
244      * Retrieve the {@link CameraCaptureSession.StateCallback} for the capture session.
245      *
246      * @return A state callback interface implementation.
247      */
getStateCallback()248     public CameraCaptureSession.StateCallback getStateCallback() {
249         return mStateCallback;
250     }
251 
252     /**
253      * Retrieve the {@link java.util.concurrent.Executor} for the capture session.
254      *
255      * @return The Executor on which the callback will be invoked.
256      */
getExecutor()257     public Executor getExecutor() {
258         return mExecutor;
259     }
260 
261     /**
262      * Sets the {@link InputConfiguration} for a reprocessable session. Input configuration are not
263      * supported for {@link #SESSION_HIGH_SPEED}.
264      *
265      * @param input Input configuration.
266      * @throws UnsupportedOperationException In case it is called for {@link #SESSION_HIGH_SPEED}
267      *                                       type session configuration.
268      */
setInputConfiguration(@onNull InputConfiguration input)269     public void setInputConfiguration(@NonNull InputConfiguration input) {
270         if (mSessionType != SESSION_HIGH_SPEED) {
271             mInputConfig = input;
272         } else {
273             throw new UnsupportedOperationException("Method not supported for high speed session" +
274                     " types");
275         }
276     }
277 
278     /**
279      * Retrieve the {@link InputConfiguration}.
280      *
281      * @return The capture session input configuration.
282      */
getInputConfiguration()283     public InputConfiguration getInputConfiguration() {
284         return mInputConfig;
285     }
286 
287     /**
288      * Sets the session wide camera parameters (see {@link CaptureRequest}). This argument can
289      * be set for every supported session type and will be passed to the camera device as part
290      * of the capture session initialization. Session parameters are a subset of the available
291      * capture request parameters (see {@link CameraCharacteristics#getAvailableSessionKeys})
292      * and their application can introduce internal camera delays. To improve camera performance
293      * it is suggested to change them sparingly within the lifetime of the capture session and
294      * to pass their initial values as part of this method.
295      *
296      * @param params A capture request that includes the initial values for any available
297      *               session wide capture keys. Tags (see {@link CaptureRequest.Builder#setTag}) and
298      *               output targets (see {@link CaptureRequest.Builder#addTarget}) are ignored if
299      *               set. Parameter values not part of
300      *               {@link CameraCharacteristics#getAvailableSessionKeys} will also be ignored. It
301      *               is recommended to build the session parameters using the same template type as
302      *               the initial capture request, so that the session and initial request parameters
303      *               match as much as possible.
304      */
setSessionParameters(CaptureRequest params)305     public void setSessionParameters(CaptureRequest params) {
306         mSessionParameters = params;
307     }
308 
309     /**
310      * Retrieve the session wide camera parameters (see {@link CaptureRequest}).
311      *
312      * @return A capture request that includes the initial values for any available
313      *         session wide capture keys.
314      */
getSessionParameters()315     public CaptureRequest getSessionParameters() {
316         return mSessionParameters;
317     }
318 
319     /**
320      * Set a specific device-supported color space.
321      *
322      * <p>Clients can choose from any profile advertised as supported in
323      * {@link CameraCharacteristics#REQUEST_AVAILABLE_COLOR_SPACE_PROFILES}
324      * queried using {@link ColorSpaceProfiles#getSupportedColorSpaces}.
325      * When set, the colorSpace will override the default color spaces of the output targets,
326      * or the color space implied by the dataSpace passed into an {@link ImageReader}'s
327      * constructor.</p>
328      */
setColorSpace(@onNull ColorSpace.Named colorSpace)329     public void setColorSpace(@NonNull ColorSpace.Named colorSpace) {
330         mColorSpace = colorSpace.ordinal();
331         for (OutputConfiguration outputConfiguration : mOutputConfigurations) {
332             outputConfiguration.setColorSpace(colorSpace);
333         }
334     }
335 
336     /**
337      * Clear the color space, such that the default color space will be used.
338      */
clearColorSpace()339     public void clearColorSpace() {
340         mColorSpace = ColorSpaceProfiles.UNSPECIFIED;
341         for (OutputConfiguration outputConfiguration : mOutputConfigurations) {
342             outputConfiguration.clearColorSpace();
343         }
344     }
345 
346     /**
347      * Return the current color space.
348      *
349      * @return the currently set color space
350      */
351     @SuppressLint("MethodNameUnits")
getColorSpace()352     public @Nullable ColorSpace getColorSpace() {
353         if (mColorSpace != ColorSpaceProfiles.UNSPECIFIED) {
354             return ColorSpace.get(ColorSpace.Named.values()[mColorSpace]);
355         } else {
356             return null;
357         }
358     }
359 }
360