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