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