Merge changes from topic "stream_combinations"

* changes:
  Camera: Implement legacy device stream combination query
  Camera: Add reprocessable mandatory stream combinations
  Camera: Add support for mandatory stream combinations
This commit is contained in:
TreeHugger Robot
2018-12-14 10:03:07 +00:00
committed by Android (Google) Code Review
9 changed files with 1453 additions and 11 deletions

View File

@@ -16583,6 +16583,7 @@ package android.hardware.camera2 {
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Byte> REQUEST_PIPELINE_MAX_DEPTH;
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SCALER_CROPPING_TYPE;
field public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_STREAM_COMBINATIONS;
field public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.StreamConfigurationMap> SCALER_STREAM_CONFIGURATION_MAP;
field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SENSOR_AVAILABLE_TEST_PATTERN_MODES;
field public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.BlackLevelPattern> SENSOR_BLACK_LEVEL_PATTERN;
@@ -17153,6 +17154,18 @@ package android.hardware.camera2.params {
field public static final float MINIMUM_GAIN_FACTOR = 1.0f;
}
public final class MandatoryStreamCombination {
method public java.lang.String getDescription();
method public java.util.List<android.hardware.camera2.params.MandatoryStreamCombination.MandatoryStreamInformation> getStreamsInformation();
method public boolean isReprocessable();
}
public static final class MandatoryStreamCombination.MandatoryStreamInformation {
method public java.util.List<android.util.Size> getAvailableSizes();
method public int getFormat();
method public boolean isInput();
}
public final class MeteringRectangle {
ctor public MeteringRectangle(int, int, int, int, int);
ctor public MeteringRectangle(android.graphics.Point, android.util.Size, int);

View File

@@ -24,6 +24,8 @@ import android.hardware.camera2.impl.PublicKey;
import android.hardware.camera2.impl.SyntheticKey;
import android.hardware.camera2.params.RecommendedStreamConfigurationMap;
import android.hardware.camera2.params.SessionConfiguration;
import android.hardware.camera2.params.MandatoryStreamCombination;
import android.hardware.camera2.params.MandatoryStreamCombination.MandatoryStreamInformation;
import android.hardware.camera2.utils.ArrayUtils;
import android.hardware.camera2.utils.TypeReference;
import android.util.Rational;
@@ -2608,6 +2610,39 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
public static final Key<android.hardware.camera2.params.ReprocessFormatsMap> SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP =
new Key<android.hardware.camera2.params.ReprocessFormatsMap>("android.scaler.availableRecommendedInputOutputFormatsMap", android.hardware.camera2.params.ReprocessFormatsMap.class);
/**
* <p>An array of mandatory stream combinations generated according to the camera device
* {@link android.hardware.camera2.CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL }
* and {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES }.
* This is an app-readable conversion of the mandatory stream combination
* {@link android.hardware.camera2.CameraDevice#createCaptureSession tables}.</p>
* <p>The array of
* {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
* generated according to the documented
* {@link android.hardware.camera2.CameraDevice#createCaptureSession guideline} based on
* specific device level and capabilities.
* Clients can use the array as a quick reference to find an appropriate camera stream
* combination.
* As per documentation, the stream combinations with given PREVIEW, RECORD and
* MAXIMUM resolutions and anything smaller from the list given by
* {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes } are
* guaranteed to work.
* The mandatory stream combination array will be {@code null} in case the device is a
* physical camera not independently exposed in
* {@link android.hardware.camera2.CameraManager#getCameraIdList } or is not backward
* compatible.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* <p><b>Limited capability</b> -
* Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
* {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
*
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
*/
@PublicKey
@SyntheticKey
public static final Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_STREAM_COMBINATIONS =
new Key<android.hardware.camera2.params.MandatoryStreamCombination[]>("android.scaler.mandatoryStreamCombinations", android.hardware.camera2.params.MandatoryStreamCombination[].class);
/**
* <p>The area of the image sensor which corresponds to active pixels after any geometric
* distortion correction has been applied.</p>

View File

@@ -435,9 +435,13 @@ public abstract class CameraDevice implements AutoCloseable {
* </table><br>
* </p>
*
* <p>Clients can access the above mandatory stream combination tables via
* {@link android.hardware.camera2.params.MandatoryStreamCombination}.</p>
*
* <p>Since the capabilities of camera devices vary greatly, a given camera device may support
* target combinations with sizes outside of these guarantees, but this can only be tested for
* by attempting to create a session with such targets.</p>
* by calling {@link #isSessionConfigurationSupported} or attempting to create a session with
* such targets.</p>
*
* @param outputs The new set of Surfaces that should be made available as
* targets for captured image data.
@@ -619,6 +623,9 @@ public abstract class CameraDevice implements AutoCloseable {
* </table><br>
* </p>
*
* <p>Clients can access the above mandatory stream combination tables via
* {@link android.hardware.camera2.params.MandatoryStreamCombination}.</p>
*
* @param inputConfig The configuration for the input {@link Surface}
* @param outputs The new set of Surfaces that should be made available as
* targets for captured image data.
@@ -980,6 +987,12 @@ public abstract class CameraDevice implements AutoCloseable {
* It must not impact normal camera behavior in any way and must complete significantly
* faster than creating a regular or constrained capture session.</p>
*
* <p>Although this method is faster than creating a new capture session, it is not intended
* to be used for exploring the entire space of supported stream combinations. The available
* mandatory stream combinations
* {@link android.hardware.camera2.params.MandatoryStreamCombination} are better suited for this
* purpose.</p>
*
* <p>Note that session parameters will be ignored and calls to
* {@link SessionConfiguration#setSessionParameters} are not required.</p>
*

View File

@@ -40,6 +40,9 @@ import android.os.ServiceSpecificException;
import android.os.SystemProperties;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Size;
import android.view.Display;
import android.view.WindowManager;
import java.util.ArrayList;
import java.util.Arrays;
@@ -231,6 +234,30 @@ public final class CameraManager {
CameraManagerGlobal.get().unregisterTorchCallback(callback);
}
private Size getDisplaySize() {
Size ret = new Size(0, 0);
try {
WindowManager windowManager =
(WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
if (height > width) {
height = width;
width = display.getHeight();
}
ret = new Size(width, height);
} catch (Exception e) {
Log.e(TAG, "getDisplaySize Failed. " + e.toString());
}
return ret;
}
/**
* <p>Query the capabilities of a camera device. These capabilities are
* immutable for a given camera.</p>
@@ -269,6 +296,8 @@ public final class CameraManager {
"Camera service is currently unavailable");
}
try {
Size displaySize = getDisplaySize();
// First check isHiddenPhysicalCamera to avoid supportsCamera2ApiLocked throwing
// exception in case cameraId is a hidden physical camera.
if (!isHiddenPhysicalCamera(cameraId) && !supportsCamera2ApiLocked(cameraId)) {
@@ -280,10 +309,19 @@ public final class CameraManager {
CameraInfo info = cameraService.getCameraInfo(id);
characteristics = LegacyMetadataMapper.createCharacteristics(parameters, info);
characteristics = LegacyMetadataMapper.createCharacteristics(parameters, info,
id, displaySize);
} else {
// Normal path: Get the camera characteristics directly from the camera service
CameraMetadataNative info = cameraService.getCameraCharacteristics(cameraId);
if (!isHiddenPhysicalCamera(cameraId)) {
try {
info.setCameraId(Integer.parseInt(cameraId));
} catch (NumberFormatException e) {
Log.e(TAG, "Failed to parse camera Id " + cameraId + " to integer");
}
}
info.setDisplaySize(displaySize);
characteristics = new CameraCharacteristics(info);
}
@@ -363,7 +401,8 @@ public final class CameraManager {
}
Log.i(TAG, "Using legacy camera HAL.");
cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);
cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id,
getDisplaySize());
}
} catch (ServiceSpecificException e) {
if (e.errorCode == ICameraService.ERROR_DEPRECATED_HAL) {

View File

@@ -51,6 +51,8 @@ import android.hardware.camera2.marshal.impl.MarshalQueryableString;
import android.hardware.camera2.params.Face;
import android.hardware.camera2.params.HighSpeedVideoConfiguration;
import android.hardware.camera2.params.LensShadingMap;
import android.hardware.camera2.params.MandatoryStreamCombination;
import android.hardware.camera2.params.MandatoryStreamCombination.MandatoryStreamInformation;
import android.hardware.camera2.params.OisSample;
import android.hardware.camera2.params.RecommendedStreamConfiguration;
import android.hardware.camera2.params.RecommendedStreamConfigurationMap;
@@ -75,6 +77,7 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* Implementation of camera metadata marshal/unmarshal across Binder to
@@ -576,6 +579,15 @@ public class CameraMetadataNative implements Parcelable {
return (T) metadata.getStreamConfigurationMap();
}
});
sGetCommandMap.put(
CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS.getNativeKey(),
new GetCommand() {
@Override
@SuppressWarnings("unchecked")
public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
return (T) metadata.getMandatoryStreamCombinations();
}
});
sGetCommandMap.put(
CameraCharacteristics.CONTROL_MAX_REGIONS_AE.getNativeKey(), new GetCommand() {
@Override
@@ -1161,6 +1173,26 @@ public class CameraMetadataNative implements Parcelable {
return ret;
}
private MandatoryStreamCombination[] getMandatoryStreamCombinations() {
int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
ArrayList<Integer> caps = new ArrayList<Integer>();
caps.ensureCapacity(capabilities.length);
for (int c : capabilities) {
caps.add(new Integer(c));
}
int hwLevel = getBase(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
MandatoryStreamCombination.Builder build = new MandatoryStreamCombination.Builder(
mCameraId, hwLevel, mDisplaySize, caps, getStreamConfigurationMap());
List<MandatoryStreamCombination> combs = build.getAvailableMandatoryStreamCombinations();
if ((combs != null) && (!combs.isEmpty())) {
MandatoryStreamCombination[] combArray = new MandatoryStreamCombination[combs.size()];
combArray = combs.toArray(combArray);
return combArray;
}
return null;
}
private StreamConfigurationMap getStreamConfigurationMap() {
StreamConfiguration[] configurations = getBase(
CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
@@ -1433,6 +1465,31 @@ public class CameraMetadataNative implements Parcelable {
return true;
}
private int mCameraId = -1;
private Size mDisplaySize = new Size(0, 0);
/**
* Set the current camera Id.
*
* @param cameraId Current camera id.
*
* @hide
*/
public void setCameraId(int cameraId) {
mCameraId = cameraId;
}
/**
* Set the current display size.
*
* @param displaySize The current display size.
*
* @hide
*/
public void setDisplaySize(Size displaySize) {
mDisplaySize = displaySize;
}
@UnsupportedAppUsage
private long mMetadataPtr; // native CameraMetadata*
@@ -1476,6 +1533,8 @@ public class CameraMetadataNative implements Parcelable {
*/
public void swap(CameraMetadataNative other) {
nativeSwap(other);
mCameraId = other.mCameraId;
mDisplaySize = other.mDisplaySize;
}
/**

View File

@@ -39,6 +39,7 @@ import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.util.Log;
import android.util.Size;
import android.util.SparseArray;
import android.view.Surface;
@@ -356,7 +357,7 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
}
public static CameraDeviceUserShim connectBinderShim(ICameraDeviceCallbacks callbacks,
int cameraId) {
int cameraId, Size displaySize) {
if (DEBUG) {
Log.d(TAG, "Opening shim Camera device");
}
@@ -393,7 +394,8 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
}
CameraCharacteristics characteristics =
LegacyMetadataMapper.createCharacteristics(legacyParameters, info);
LegacyMetadataMapper.createCharacteristics(legacyParameters, info, cameraId,
displaySize);
LegacyCameraDevice device = new LegacyCameraDevice(
cameraId, legacyCamera, characteristics, threadCallbacks);
return new CameraDeviceUserShim(cameraId, device, characteristics, init, threadCallbacks);
@@ -482,8 +484,38 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
@Override
public boolean isSessionConfigurationSupported(SessionConfiguration sessionConfig) {
// TODO: Add support for this in legacy mode
throw new UnsupportedOperationException("Session configuration query not supported!");
if (sessionConfig.getSessionType() != SessionConfiguration.SESSION_REGULAR) {
Log.e(TAG, "Session type: " + sessionConfig.getSessionType() + " is different from " +
" regular. Legacy devices support only regular session types!");
return false;
}
if (sessionConfig.getInputConfiguration() != null) {
Log.e(TAG, "Input configuration present, legacy devices do not support this feature!");
return false;
}
List<OutputConfiguration> outputConfigs = sessionConfig.getOutputConfigurations();
if (outputConfigs.isEmpty()) {
Log.e(TAG, "Empty output configuration list!");
return false;
}
SparseArray<Surface> surfaces = new SparseArray<Surface>(outputConfigs.size());
int idx = 0;
for (OutputConfiguration outputConfig : outputConfigs) {
List<Surface> surfaceList = outputConfig.getSurfaces();
if (surfaceList.isEmpty() || (surfaceList.size() > 1)) {
Log.e(TAG, "Legacy devices do not support deferred or shared surfaces!");
return false;
}
surfaces.put(idx++, outputConfig.getSurface());
}
int ret = mLegacyDevice.configureOutputs(surfaces, /*validateSurfacesOnly*/true);
return ret == LegacyExceptionUtils.NO_ERROR;
}
@Override

View File

@@ -346,6 +346,25 @@ public class LegacyCameraDevice implements AutoCloseable {
* on success.
*/
public int configureOutputs(SparseArray<Surface> outputs) {
return configureOutputs(outputs, /*validateSurfacesOnly*/false);
}
/**
* Configure the device with a set of output surfaces.
*
* <p>Using empty or {@code null} {@code outputs} is the same as unconfiguring.</p>
*
* <p>Every surface in {@code outputs} must be non-{@code null}.</p>
*
* @param outputs a list of surfaces to set. LegacyCameraDevice will take ownership of this
* list; it must not be modified by the caller once it's passed in.
* @param validateSurfacesOnly If set it will only check whether the outputs are supported
* and avoid any device configuration.
* @return an error code for this binder operation, or {@link NO_ERROR}
* on success.
* @hide
*/
public int configureOutputs(SparseArray<Surface> outputs, boolean validateSurfacesOnly) {
List<Pair<Surface, Size>> sizedSurfaces = new ArrayList<>();
if (outputs != null) {
int count = outputs.size();
@@ -397,7 +416,9 @@ public class LegacyCameraDevice implements AutoCloseable {
sizedSurfaces.add(new Pair<>(output, s));
}
// Lock down the size before configuration
setSurfaceDimens(output, s.getWidth(), s.getHeight());
if (!validateSurfacesOnly) {
setSurfaceDimens(output, s.getWidth(), s.getHeight());
}
} catch (BufferQueueAbandonedException e) {
Log.e(TAG, "Surface bufferqueue is abandoned, cannot configure as output: ", e);
return BAD_VALUE;
@@ -406,6 +427,10 @@ public class LegacyCameraDevice implements AutoCloseable {
}
}
if (validateSurfacesOnly) {
return LegacyExceptionUtils.NO_ERROR;
}
boolean success = false;
if (mDeviceState.setConfiguring()) {
mRequestThreadManager.configure(sizedSurfaces);

View File

@@ -111,13 +111,15 @@ public class LegacyMetadataMapper {
*
* @param parameters A non-{@code null} parameters set
* @param info Camera info with camera facing direction and angle of orientation
* @param cameraId Current camera Id
* @param displaySize Device display size
*
* @return static camera characteristics for a camera device
*
* @throws NullPointerException if any of the args were {@code null}
*/
public static CameraCharacteristics createCharacteristics(Camera.Parameters parameters,
CameraInfo info) {
CameraInfo info, int cameraId, Size displaySize) {
checkNotNull(parameters, "parameters must not be null");
checkNotNull(info, "info must not be null");
@@ -125,7 +127,7 @@ public class LegacyMetadataMapper {
android.hardware.CameraInfo outerInfo = new android.hardware.CameraInfo();
outerInfo.info = info;
return createCharacteristics(paramStr, outerInfo);
return createCharacteristics(paramStr, outerInfo, cameraId, displaySize);
}
/**
@@ -134,12 +136,14 @@ public class LegacyMetadataMapper {
*
* @param parameters A string parseable by {@link Camera.Parameters#unflatten}
* @param info Camera info with camera facing direction and angle of orientation
* @param cameraId Current camera id
* @param displaySize Device display size
* @return static camera characteristics for a camera device
*
* @throws NullPointerException if any of the args were {@code null}
*/
public static CameraCharacteristics createCharacteristics(String parameters,
android.hardware.CameraInfo info) {
android.hardware.CameraInfo info, int cameraId, Size displaySize) {
checkNotNull(parameters, "parameters must not be null");
checkNotNull(info, "info must not be null");
checkNotNull(info.info, "info.info must not be null");
@@ -159,6 +163,9 @@ public class LegacyMetadataMapper {
Log.v(TAG, "--------------------------------------------------- (end)");
}
m.setCameraId(cameraId);
m.setDisplaySize(displaySize);
return new CameraCharacteristics(m);
}

File diff suppressed because it is too large Load Diff