summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
authorZhijun He <zhijunhe@google.com>2015-06-01 16:36:06 -0700
committerZhijun He <zhijunhe@google.com>2015-06-04 15:22:00 -0700
commita7677722304670dc07feef242156b97e6bb51bcd (patch)
tree2745720687e323dbd4a248f2368e2e42a6d339ec /core/java
parentf1bbdf5182107aa7779cd1a91d8652f04fa1b399 (diff)
downloadframeworks_base-a7677722304670dc07feef242156b97e6bb51bcd.zip
frameworks_base-a7677722304670dc07feef242156b97e6bb51bcd.tar.gz
frameworks_base-a7677722304670dc07feef242156b97e6bb51bcd.tar.bz2
Camera2: implement high speed video APIs
Bug: 21442271 Change-Id: Ia0ae5bbd3e8c81bad293c29987301a2457817d12
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java46
-rw-r--r--core/java/android/hardware/camera2/ICameraDeviceUser.aidl2
-rw-r--r--core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java44
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDeviceImpl.java183
-rw-r--r--core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java2
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java37
-rw-r--r--core/java/android/hardware/camera2/utils/SurfaceUtils.java80
7 files changed, 375 insertions, 19 deletions
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index b2c1c71..bc625dd 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -169,6 +169,9 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
private final HashSet<Surface> mSurfaceSet;
private final CameraMetadataNative mSettings;
private boolean mIsReprocess;
+ // If this request is part of constrained high speed request list that was created by
+ // {@link CameraDevice#createConstrainedHighSpeedRequestList}.
+ private boolean mIsPartOfCHSRequestList = false;
// Each reprocess request must be tied to a reprocessable session ID.
// Valid only for reprocess requests (mIsReprocess == true).
private int mReprocessableSessionId;
@@ -197,6 +200,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
mSettings = new CameraMetadataNative(source.mSettings);
mSurfaceSet = (HashSet<Surface>) source.mSurfaceSet.clone();
mIsReprocess = source.mIsReprocess;
+ mIsPartOfCHSRequestList = source.mIsPartOfCHSRequestList;
mReprocessableSessionId = source.mReprocessableSessionId;
mUserTag = source.mUserTag;
}
@@ -321,6 +325,35 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
}
/**
+ * <p>Determine if this request is part of a constrained high speed request list that was
+ * created by {@link CameraDevice#createConstrainedHighSpeedRequestList}. A constrained high
+ * speed request list contains some constrained high speed capture requests with certain
+ * interleaved pattern that is suitable for high speed preview/video streaming. An active
+ * constrained high speed capture session only accepts constrained high speed request lists.
+ * This method can be used to do the sanity check when a constrained high speed capture session
+ * receives a request list via {@link CameraCaptureSession#setRepeatingBurst} or
+ * {@link CameraCaptureSession#captureBurst}.
+ * </p>
+ *
+ *
+ * @return {@code true} if this request is part of a constrained high speed request list,
+ * {@code false} otherwise.
+ *
+ * @hide
+ */
+ public boolean isPartOfCRequestList() {
+ return mIsPartOfCHSRequestList;
+ }
+
+ /**
+ * Returns a copy of the underlying {@link CameraMetadataNative}.
+ * @hide
+ */
+ public CameraMetadataNative getNativeCopy() {
+ return new CameraMetadataNative(mSettings);
+ }
+
+ /**
* Get the reprocessable session ID this reprocess capture request is associated with.
*
* @return the reprocessable session ID this reprocess capture request is associated with
@@ -547,6 +580,18 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
}
/**
+ * <p>Mark this request as part of a constrained high speed request list created by
+ * {@link CameraDevice#createConstrainedHighSpeedRequestList}. A constrained high speed
+ * request list contains some constrained high speed capture requests with certain
+ * interleaved pattern that is suitable for high speed preview/video streaming.</p>
+ *
+ * @hide
+ */
+ public void setPartOfCHSRequestList(boolean partOfCHSList) {
+ mRequest.mIsPartOfCHSRequestList = partOfCHSList;
+ }
+
+ /**
* Build a request using the current target Surfaces and settings.
* <p>Note that, although it is possible to create a {@code CaptureRequest} with no target
* {@link Surface}s, passing such a request into {@link CameraCaptureSession#capture},
@@ -563,7 +608,6 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
return new CaptureRequest(mRequest);
}
-
/**
* @hide
*/
diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
index 375b310..1574f93 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -61,7 +61,7 @@ interface ICameraDeviceUser
* must be called before any requests can be submitted.
* <p>
*/
- int endConfigure();
+ int endConfigure(boolean isConstrainedHighSpeed);
int deleteStream(int streamId);
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index ab0f607..cbc85f3 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -60,6 +60,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
private final android.hardware.camera2.impl.CameraDeviceImpl mDeviceImpl;
/** Internal handler; used for all incoming events to preserve total order */
private final Handler mDeviceHandler;
+ private final boolean mIsConstrainedHighSpeedSession;
/** Drain Sequence IDs which have been queued but not yet finished with aborted/completed */
private final TaskDrainer<Integer> mSequenceDrainer;
@@ -88,13 +89,14 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
CameraCaptureSessionImpl(int id, Surface input, List<Surface> outputs,
CameraCaptureSession.StateCallback callback, Handler stateHandler,
android.hardware.camera2.impl.CameraDeviceImpl deviceImpl,
- Handler deviceStateHandler, boolean configureSuccess) {
+ Handler deviceStateHandler, boolean configureSuccess, boolean isConstrainedHighSpeed) {
if (outputs == null || outputs.isEmpty()) {
throw new IllegalArgumentException("outputs must be a non-null, non-empty list");
} else if (callback == null) {
throw new IllegalArgumentException("callback must not be null");
}
+ mIsConstrainedHighSpeedSession = isConstrainedHighSpeed;
mId = id;
mIdString = String.format("Session %d: ", mId);
@@ -134,6 +136,30 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
}
}
+
+ private boolean isConstrainedHighSpeedRequestList(List<CaptureRequest> requestList) {
+ checkCollectionNotEmpty(requestList, "High speed request list");
+ for (CaptureRequest request : requestList) {
+ if (!request.isPartOfCRequestList()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * If the session is constrained high speed session, it only accept constrained high speed
+ * request list.
+ */
+ private void checkConstrainedHighSpeedRequestSanity(List<CaptureRequest> requestList) {
+ if (mIsConstrainedHighSpeedSession) {
+ if (!isConstrainedHighSpeedRequestList(requestList)) {
+ throw new IllegalArgumentException("It is only allowed to submit a constrained "
+ + "high speed request list to a constrianed high speed session!!!");
+ }
+ }
+ }
+
@Override
public CameraDevice getDevice() {
return mDeviceImpl;
@@ -155,6 +181,10 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
} else if (request.isReprocess() && request.getReprocessableSessionId() != mId) {
throw new IllegalArgumentException("capture request was created for another session");
}
+ if (mIsConstrainedHighSpeedSession) {
+ throw new UnsupportedOperationException("Constrained high speed session doesn't support"
+ + " this method");
+ }
checkNotClosed();
@@ -178,6 +208,8 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
throw new IllegalArgumentException("Requests must have at least one element");
}
+ checkConstrainedHighSpeedRequestSanity(requests);
+
for (CaptureRequest request : requests) {
if (request.isReprocess()) {
if (!isReprocessable()) {
@@ -212,7 +244,10 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
} else if (request.isReprocess()) {
throw new IllegalArgumentException("repeating reprocess requests are not supported");
}
-
+ if (mIsConstrainedHighSpeedSession) {
+ throw new UnsupportedOperationException("Constrained high speed session doesn't support"
+ + " this method");
+ }
checkNotClosed();
@@ -236,6 +271,8 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
throw new IllegalArgumentException("requests must have at least one element");
}
+ checkConstrainedHighSpeedRequestSanity(requests);
+
for (CaptureRequest r : requests) {
if (r.isReprocess()) {
throw new IllegalArgumentException("repeating reprocess burst requests are not " +
@@ -704,7 +741,8 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
// everything is idle.
try {
// begin transition to unconfigured
- mDeviceImpl.configureStreamsChecked(null, null);
+ mDeviceImpl.configureStreamsChecked(/*inputConfig*/null, /*outputs*/null,
+ /*isConstrainedHighSpeed*/false);
} catch (CameraAccessException e) {
// OK: do not throw checked exceptions.
Log.e(TAG, mIdString + "Exception while unconfiguring outputs: ", e);
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 16701e5..e975105 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -18,6 +18,7 @@ package android.hardware.camera2.impl;
import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
+import android.graphics.ImageFormat;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
@@ -35,17 +36,22 @@ import android.hardware.camera2.params.StreamConfigurationMap;
import android.hardware.camera2.utils.CameraBinderDecorator;
import android.hardware.camera2.utils.CameraRuntimeException;
import android.hardware.camera2.utils.LongParcelable;
+import android.hardware.camera2.utils.SurfaceUtils;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
+import android.util.Range;
import android.util.Size;
import android.util.SparseArray;
import android.view.Surface;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -326,7 +332,8 @@ public class CameraDeviceImpl extends CameraDevice {
for (Surface s : outputs) {
outputConfigs.add(new OutputConfiguration(s));
}
- configureStreamsChecked(/*inputConfig*/null, outputConfigs);
+ configureStreamsChecked(/*inputConfig*/null, outputConfigs,
+ /*isConstrainedHighSpeed*/false);
}
@@ -344,12 +351,14 @@ public class CameraDeviceImpl extends CameraDevice {
*
* @param inputConfig input configuration or {@code null} for no input
* @param outputs a list of one or more surfaces, or {@code null} to unconfigure
+ * @param isConstrainedHighSpeed If the streams configuration is for constrained high speed output.
* @return whether or not the configuration was successful
*
* @throws CameraAccessException if there were any unexpected problems during configuration
*/
public boolean configureStreamsChecked(InputConfiguration inputConfig,
- List<OutputConfiguration> outputs) throws CameraAccessException {
+ List<OutputConfiguration> outputs, boolean isConstrainedHighSpeed)
+ throws CameraAccessException {
// Treat a null input the same an empty list
if (outputs == null) {
outputs = new ArrayList<OutputConfiguration>();
@@ -422,7 +431,7 @@ public class CameraDeviceImpl extends CameraDevice {
}
try {
- mRemoteDevice.endConfigure();
+ mRemoteDevice.endConfigure(isConstrainedHighSpeed);
}
catch (IllegalArgumentException e) {
// OK. camera service can reject stream config if it's not supported by HAL
@@ -463,7 +472,8 @@ public class CameraDeviceImpl extends CameraDevice {
for (Surface surface : outputs) {
outConfigurations.add(new OutputConfiguration(surface));
}
- createCaptureSessionInternal(null, outConfigurations, callback, handler);
+ createCaptureSessionInternal(null, outConfigurations, callback, handler,
+ /*isConstrainedHighSpeed*/false);
}
@Override
@@ -475,7 +485,8 @@ public class CameraDeviceImpl extends CameraDevice {
Log.d(TAG, "createCaptureSessionByOutputConfiguration");
}
- createCaptureSessionInternal(null, outputConfigurations, callback, handler);
+ createCaptureSessionInternal(null, outputConfigurations, callback, handler,
+ /*isConstrainedHighSpeed*/false);
}
@Override
@@ -494,13 +505,14 @@ public class CameraDeviceImpl extends CameraDevice {
for (Surface surface : outputs) {
outConfigurations.add(new OutputConfiguration(surface));
}
- createCaptureSessionInternal(inputConfig, outConfigurations, callback, handler);
+ createCaptureSessionInternal(inputConfig, outConfigurations, callback, handler,
+ /*isConstrainedHighSpeed*/false);
}
private void createCaptureSessionInternal(InputConfiguration inputConfig,
List<OutputConfiguration> outputConfigurations,
- CameraCaptureSession.StateCallback callback, Handler handler)
- throws CameraAccessException {
+ CameraCaptureSession.StateCallback callback, Handler handler,
+ boolean isConstrainedHighSpeed) throws CameraAccessException {
synchronized(mInterfaceLock) {
if (DEBUG) {
Log.d(TAG, "createCaptureSessionInternal");
@@ -508,6 +520,11 @@ public class CameraDeviceImpl extends CameraDevice {
checkIfCameraClosedOrInError();
+ if (isConstrainedHighSpeed && inputConfig != null) {
+ throw new IllegalArgumentException("Constrained high speed session doesn't support"
+ + " input configuration yet.");
+ }
+
// Notify current session that it's going away, before starting camera operations
// After this call completes, the session is not allowed to call into CameraDeviceImpl
if (mCurrentSession != null) {
@@ -520,7 +537,8 @@ public class CameraDeviceImpl extends CameraDevice {
Surface input = null;
try {
// configure streams and then block until IDLE
- configureSuccess = configureStreamsChecked(inputConfig, outputConfigurations);
+ configureSuccess = configureStreamsChecked(inputConfig, outputConfigurations,
+ isConstrainedHighSpeed);
if (inputConfig != null) {
input = new Surface();
mRemoteDevice.getInputSurface(/*out*/input);
@@ -545,7 +563,7 @@ public class CameraDeviceImpl extends CameraDevice {
CameraCaptureSessionImpl newSession =
new CameraCaptureSessionImpl(mNextSessionId++, input,
outSurfaces, callback, handler, this, mDeviceHandler,
- configureSuccess);
+ configureSuccess, isConstrainedHighSpeed);
// TODO: wait until current session closes, then create the new session
mCurrentSession = newSession;
@@ -1907,17 +1925,156 @@ public class CameraDeviceImpl extends CameraDevice {
return mCharacteristics;
}
+ private void checkConstrainedHighSpeedSurfaces(Collection<Surface> surfaces,
+ Range<Integer> fpsRange) {
+ if (surfaces == null || surfaces.size() == 0 || surfaces.size() > 2) {
+ throw new IllegalArgumentException("Output target surface list must not be null and"
+ + " the size must be 1 or 2");
+ }
+
+ StreamConfigurationMap config =
+ getCharacteristics().get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ List<Size> highSpeedSizes = null;
+ if (fpsRange == null) {
+ highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizes());
+ } else {
+ // Check the FPS range first if provided
+ Range<Integer>[] highSpeedFpsRanges = config.getHighSpeedVideoFpsRanges();
+ if(!Arrays.asList(highSpeedFpsRanges).contains(fpsRange)) {
+ throw new IllegalArgumentException("Fps range " + fpsRange.toString() + " in the"
+ + " request is not a supported high speed fps range " +
+ Arrays.toString(highSpeedFpsRanges));
+ }
+ highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizesFor(fpsRange));
+ }
+
+ for (Surface surface : surfaces) {
+ // Surface size must be supported high speed sizes.
+ Size surfaceSize = SurfaceUtils.getSurfaceSize(surface);
+ int surfaceFormat = SurfaceUtils.getSurfaceFormat(surface);
+
+ if (surfaceFormat != ImageFormat.PRIVATE) {
+ throw new IllegalArgumentException("Surface format is not for preview or"
+ + " hardware video encoding" + surfaceFormat);
+ }
+
+ if (!highSpeedSizes.contains(surfaceSize)) {
+ throw new IllegalArgumentException("Surface size " + surfaceSize.toString() + " is"
+ + " not part of the high speed supported size list " +
+ Arrays.toString(highSpeedSizes.toArray()));
+ }
+ // Each output surface must be either preview surface or recording surface.
+ if (!SurfaceUtils.isSurfaceForPreview(surface) &&
+ !SurfaceUtils.isSurfaceForHwVideoEncoder(surface)) {
+ throw new IllegalArgumentException("This output surface is neither preview nor "
+ + "hardware video encoding surface");
+ }
+ if (SurfaceUtils.isSurfaceForPreview(surface) &&
+ SurfaceUtils.isSurfaceForHwVideoEncoder(surface)) {
+ throw new IllegalArgumentException("This output surface can not be both preview"
+ + " and hardware video encoding surface");
+ }
+ }
+
+ // For 2 output surface case, they shouldn't be same type.
+ if (surfaces.size() == 2) {
+ // Up to here, each surface can only be either preview or recording.
+ Iterator<Surface> iterator = surfaces.iterator();
+ boolean isFirstSurfacePreview =
+ SurfaceUtils.isSurfaceForPreview(iterator.next());
+ boolean isSecondSurfacePreview =
+ SurfaceUtils.isSurfaceForPreview(iterator.next());
+ if (isFirstSurfacePreview == isSecondSurfacePreview) {
+ throw new IllegalArgumentException("The 2 output surfaces must have different"
+ + " type");
+ }
+ }
+ }
+
@Override
public void createConstrainedHighSpeedCaptureSession(List<Surface> outputs,
android.hardware.camera2.CameraCaptureSession.StateCallback callback, Handler handler)
throws CameraAccessException {
- // TODO: to be implemented
- throw new UnsupportedOperationException("To be implemented!!!!");
+ if (outputs == null || outputs.size() == 0 || outputs.size() > 2) {
+ throw new IllegalArgumentException(
+ "Output surface list must not be null and the size must be no more than 2");
+ }
+ checkConstrainedHighSpeedSurfaces(outputs, /*fpsRange*/null);
+
+ List<OutputConfiguration> outConfigurations = new ArrayList<>(outputs.size());
+ for (Surface surface : outputs) {
+ outConfigurations.add(new OutputConfiguration(surface));
+ }
+ createCaptureSessionInternal(null, outConfigurations, callback, handler,
+ /*isConstrainedHighSpeed*/true);
}
@Override
public List<CaptureRequest> createConstrainedHighSpeedRequestList(CaptureRequest request)
throws CameraAccessException {
- throw new UnsupportedOperationException("To be implemented!!!!");
+ if (request == null) {
+ throw new IllegalArgumentException("Input capture request must not be null");
+ }
+ Collection<Surface> outputSurfaces = request.getTargets();
+ Range<Integer> fpsRange = request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
+ checkConstrainedHighSpeedSurfaces(outputSurfaces, fpsRange);
+
+ // Request list size: to limit the preview to 30fps, need use maxFps/30; to maximize
+ // the preview frame rate, should use maxBatch size for that high speed stream
+ // configuration. We choose the former for now.
+ int requestListSize = fpsRange.getUpper() / 30;
+ List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
+
+ // Prepare the Request builders: need carry over the request controls.
+ // First, create a request builder that will only include preview or recording target.
+ CameraMetadataNative requestMetadata = new CameraMetadataNative(request.getNativeCopy());
+ CaptureRequest.Builder singleTargetRequestBuilder = new CaptureRequest.Builder(
+ requestMetadata, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE);
+
+ // Overwrite the capture intent to make sure a good value is set.
+ Surface[] surfaces = (Surface[])outputSurfaces.toArray();
+ if (outputSurfaces.size() == 1 && SurfaceUtils.isSurfaceForHwVideoEncoder(surfaces[0])) {
+ singleTargetRequestBuilder.set(CaptureRequest.CONTROL_CAPTURE_INTENT,
+ CaptureRequest.CONTROL_CAPTURE_INTENT_PREVIEW);
+ } else {
+ // Video only, or preview + video
+ singleTargetRequestBuilder.set(CaptureRequest.CONTROL_CAPTURE_INTENT,
+ CaptureRequest.CONTROL_CAPTURE_INTENT_VIDEO_RECORD);
+ }
+ singleTargetRequestBuilder.setPartOfCHSRequestList(/*partOfCHSList*/true);
+
+ // Second, Create a request builder that will include both preview and recording targets.
+ CaptureRequest.Builder doubleTargetRequestBuilder = null;
+ if (outputSurfaces.size() == 2) {
+ doubleTargetRequestBuilder = new CaptureRequest.Builder(
+ requestMetadata, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE);
+ doubleTargetRequestBuilder.set(CaptureRequest.CONTROL_CAPTURE_INTENT,
+ CaptureRequest.CONTROL_CAPTURE_INTENT_VIDEO_RECORD);
+ doubleTargetRequestBuilder.addTarget(surfaces[0]);
+ doubleTargetRequestBuilder.addTarget(surfaces[1]);
+ doubleTargetRequestBuilder.setPartOfCHSRequestList(/*partOfCHSList*/true);
+ // Make sure singleTargetRequestBuilder contains only recording surface for
+ // preview + recording case.
+ Surface recordingSurface = surfaces[0];
+ if (!SurfaceUtils.isSurfaceForHwVideoEncoder(recordingSurface)) {
+ recordingSurface = surfaces[1];
+ }
+ singleTargetRequestBuilder.addTarget(recordingSurface);
+ } else {
+ // Single output case: either recording or preview.
+ singleTargetRequestBuilder.addTarget(surfaces[0]);
+ }
+
+ // Generate the final request list.
+ for (int i = 0; i < requestListSize; i++) {
+ if (i == 0 && doubleTargetRequestBuilder != null) {
+ // First request should be recording + preview request
+ requestList.add(doubleTargetRequestBuilder.build());
+ } else {
+ requestList.add(singleTargetRequestBuilder.build());
+ }
+ }
+
+ return Collections.unmodifiableList(requestList);
}
}
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index bc0a3a8..e963a0d 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -465,7 +465,7 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
}
@Override
- public int endConfigure() {
+ public int endConfigure(boolean isConstrainedHighSpeed) {
if (DEBUG) {
Log.d(TAG, "endConfigure called.");
}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index 098c2d8..cc9d496 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -82,6 +82,7 @@ public class LegacyCameraDevice implements AutoCloseable {
private static final int GRALLOC_USAGE_SW_READ_OFTEN = 0x00000003;
private static final int GRALLOC_USAGE_HW_TEXTURE = 0x00000100;
private static final int GRALLOC_USAGE_HW_COMPOSER = 0x00000800;
+ private static final int GRALLOC_USAGE_HW_RENDER = 0x00000200;
private static final int GRALLOC_USAGE_HW_VIDEO_ENCODER = 0x00010000;
public static final int MAX_DIMEN_FOR_ROUNDING = 1080; // maximum allowed width for rounding
@@ -549,6 +550,42 @@ public class LegacyCameraDevice implements AutoCloseable {
return flexibleConsumer;
}
+ public static boolean isPreviewConsumer(Surface output) {
+ int usageFlags = detectSurfaceUsageFlags(output);
+ int disallowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_RENDERSCRIPT |
+ GRALLOC_USAGE_SW_READ_OFTEN;
+ int allowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER |
+ GRALLOC_USAGE_HW_RENDER;
+ boolean previewConsumer = ((usageFlags & disallowedFlags) == 0 &&
+ (usageFlags & allowedFlags) != 0);
+ int surfaceFormat = ImageFormat.UNKNOWN;
+ try {
+ surfaceFormat = detectSurfaceType(output);
+ } catch(BufferQueueAbandonedException e) {
+ throw new IllegalArgumentException("Surface was abandoned", e);
+ }
+
+ return previewConsumer && (surfaceFormat == ImageFormat.PRIVATE);
+ }
+
+ public static boolean isVideoEncoderConsumer(Surface output) {
+ int usageFlags = detectSurfaceUsageFlags(output);
+ int disallowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER |
+ GRALLOC_USAGE_RENDERSCRIPT | GRALLOC_USAGE_SW_READ_OFTEN;
+ int allowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER;
+ boolean videoEncoderConsumer = ((usageFlags & disallowedFlags) == 0 &&
+ (usageFlags & allowedFlags) != 0);
+
+ int surfaceFormat = ImageFormat.UNKNOWN;
+ try {
+ surfaceFormat = detectSurfaceType(output);
+ } catch(BufferQueueAbandonedException e) {
+ throw new IllegalArgumentException("Surface was abandoned", e);
+ }
+
+ return videoEncoderConsumer && (surfaceFormat == ImageFormat.PRIVATE);
+ }
+
/**
* Query the surface for its currently configured usage flags
*/
diff --git a/core/java/android/hardware/camera2/utils/SurfaceUtils.java b/core/java/android/hardware/camera2/utils/SurfaceUtils.java
new file mode 100644
index 0000000..79d82a8
--- /dev/null
+++ b/core/java/android/hardware/camera2/utils/SurfaceUtils.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.utils;
+
+import android.hardware.camera2.legacy.LegacyCameraDevice;
+import android.hardware.camera2.legacy.LegacyExceptionUtils.BufferQueueAbandonedException;
+import android.util.Size;
+import android.view.Surface;
+
+/**
+ * Various Surface utilities.
+ */
+public class SurfaceUtils {
+
+ /**
+ * Check if a surface is for preview consumer.
+ *
+ * @param surface The surface to be checked.
+ * @return true if the surface is for preview consumer, false otherwise.
+ */
+ public static boolean isSurfaceForPreview(Surface surface) {
+ return LegacyCameraDevice.isPreviewConsumer(surface);
+ }
+
+ /**
+ * Check if the surface is for hardware video encoder consumer.
+ *
+ * @param surface The surface to be checked.
+ * @return true if the surface is for hardware video encoder consumer, false otherwise.
+ */
+ public static boolean isSurfaceForHwVideoEncoder(Surface surface) {
+ return LegacyCameraDevice.isVideoEncoderConsumer(surface);
+ }
+
+ /**
+ * Get the Surface size.
+ *
+ * @param surface The surface to be queried for size.
+ * @return Size of the surface.
+ *
+ * @throw IllegalArgumentException if the surface is already abandoned.
+ */
+ public static Size getSurfaceSize(Surface surface) {
+ try {
+ return LegacyCameraDevice.getSurfaceSize(surface);
+ } catch (BufferQueueAbandonedException e) {
+ throw new IllegalArgumentException("Surface was abandoned", e);
+ }
+ }
+
+ /**
+ * Get the Surface format.
+ *
+ * @param surface The surface to be queried for format.
+ * @return format of the surface.
+ *
+ * @throw IllegalArgumentException if the surface is already abandoned.
+ */
+ public static int getSurfaceFormat(Surface surface) {
+ try {
+ return LegacyCameraDevice.detectSurfaceType(surface);
+ } catch (BufferQueueAbandonedException e) {
+ throw new IllegalArgumentException("Surface was abandoned", e);
+ }
+ }
+}