Merge "Camera: Add multi-resolution image reader and reprocessing support" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
71ecb60a5a
@@ -24,13 +24,11 @@ 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.utils.ArrayUtils;
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
import android.os.Build;
|
||||
import android.util.Rational;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -641,27 +639,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
|
||||
*/
|
||||
@NonNull
|
||||
public Set<String> getPhysicalCameraIds() {
|
||||
int[] availableCapabilities = get(REQUEST_AVAILABLE_CAPABILITIES);
|
||||
if (availableCapabilities == null) {
|
||||
throw new AssertionError("android.request.availableCapabilities must be non-null "
|
||||
+ "in the characteristics");
|
||||
}
|
||||
|
||||
if (!ArrayUtils.contains(availableCapabilities,
|
||||
REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
byte[] physicalCamIds = get(LOGICAL_MULTI_CAMERA_PHYSICAL_IDS);
|
||||
|
||||
String physicalCamIdString = null;
|
||||
try {
|
||||
physicalCamIdString = new String(physicalCamIds, "UTF-8");
|
||||
} catch (java.io.UnsupportedEncodingException e) {
|
||||
throw new AssertionError("android.logicalCam.physicalIds must be UTF-8 string");
|
||||
}
|
||||
String[] physicalCameraIdArray = physicalCamIdString.split("\0");
|
||||
|
||||
return Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(physicalCameraIdArray)));
|
||||
return mProperties.getPhysicalCameraIds();
|
||||
}
|
||||
|
||||
/*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
|
||||
@@ -2930,6 +2908,74 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
|
||||
public static final Key<android.util.Size> SCALER_DEFAULT_SECURE_IMAGE_SIZE =
|
||||
new Key<android.util.Size>("android.scaler.defaultSecureImageSize", android.util.Size.class);
|
||||
|
||||
/**
|
||||
* <p>The available multi-resolution stream configurations that this
|
||||
* physical camera device supports
|
||||
* (i.e. format, width, height, output/input stream).</p>
|
||||
* <p>This list contains a subset of the parent logical camera's multi-resolution stream
|
||||
* configurations which belong to this physical camera, and it will advertise and will only
|
||||
* advertise the maximum supported resolutions for a particular format.</p>
|
||||
* <p>If this camera device isn't a physical camera device constituting a logical camera,
|
||||
* but a standalone ULTRA_HIGH_RESOLUTION_SENSOR camera, this field represents the
|
||||
* multi-resolution input/output stream configurations of default mode and max resolution
|
||||
* modes. The sizes will be the maximum resolution of a particular format for default mode
|
||||
* and max resolution mode.</p>
|
||||
* <p>This field will only be advertised if the device is a physical camera of a
|
||||
* logical multi-camera device or an ultra high resolution sensor camera. For a logical
|
||||
* multi-camera, the camera API will derive the logical camera’s multi-resolution stream
|
||||
* configurations from all physical cameras. For an ultra high resolution sensor camera, this
|
||||
* is used directly as the camera’s multi-resolution stream configurations.</p>
|
||||
* <p><b>Optional</b> - The value for this key 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
|
||||
* @hide
|
||||
*/
|
||||
public static final Key<android.hardware.camera2.params.StreamConfiguration[]> SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS =
|
||||
new Key<android.hardware.camera2.params.StreamConfiguration[]>("android.scaler.physicalCameraMultiResolutionStreamConfigurations", android.hardware.camera2.params.StreamConfiguration[].class);
|
||||
|
||||
/**
|
||||
* <p>The multi-resolution stream configurations supported by this logical camera
|
||||
* or ultra high resolution sensor camera device.</p>
|
||||
* <p>Multi-resolution streams can be used by a LOGICAL_MULTI_CAMERA or an
|
||||
* ULTRA_HIGH_RESOLUTION_SENSOR camera where the images sent or received can vary in
|
||||
* resolution per frame. This is useful in cases where the camera device's effective full
|
||||
* resolution changes depending on factors such as the current zoom level, lighting
|
||||
* condition, focus distance, or pixel mode.</p>
|
||||
* <ul>
|
||||
* <li>For a logical multi-camera implementing optical zoom, at different zoom level, a
|
||||
* different physical camera may be active, resulting in different full-resolution image
|
||||
* sizes.</li>
|
||||
* <li>For an ultra high resolution camera, depending on whether the camera operates in default
|
||||
* mode, or maximum resolution mode, the output full-size images may be of either binned
|
||||
* resolution or maximum resolution.</li>
|
||||
* </ul>
|
||||
* <p>To use multi-resolution output streams, the supported formats can be queried by {@link android.hardware.camera2.params.MultiResolutionStreamConfigurationMap#getOutputFormats }.
|
||||
* A {@link android.hardware.camera2.MultiResolutionImageReader } can then be created for a
|
||||
* supported format with the MultiResolutionStreamInfo group queried by {@link android.hardware.camera2.params.MultiResolutionStreamConfigurationMap#getOutputInfo }.</p>
|
||||
* <p>If a camera device supports multi-resolution output streams for a particular format, for
|
||||
* each of its mandatory stream combinations, the camera device will support using a
|
||||
* MultiResolutionImageReader for the MAXIMUM stream of supported formats. Refer to
|
||||
* {@link android.hardware.camera2.CameraDevice#createCaptureSession } for additional details.</p>
|
||||
* <p>To use multi-resolution input streams, the supported formats can be queried by {@link android.hardware.camera2.params.MultiResolutionStreamConfigurationMap#getInputFormats }.
|
||||
* A reprocessable CameraCaptureSession can then be created using an {@link android.hardware.camera2.params.InputConfiguration InputConfiguration} constructed with
|
||||
* the input MultiResolutionStreamInfo group, queried by {@link android.hardware.camera2.params.MultiResolutionStreamConfigurationMap#getInputInfo }.</p>
|
||||
* <p>If a camera device supports multi-resolution {@code YUV} input and multi-resolution
|
||||
* {@code YUV} output, or multi-resolution {@code PRIVATE} input and multi-resolution
|
||||
* {@code PRIVATE} output, {@code JPEG} and {@code YUV} are guaranteed to be supported
|
||||
* multi-resolution output stream formats. Refer to
|
||||
* {@link android.hardware.camera2.CameraDevice#createCaptureSession } for
|
||||
* details about the additional mandatory stream combinations in this case.</p>
|
||||
* <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
|
||||
*/
|
||||
@PublicKey
|
||||
@NonNull
|
||||
@SyntheticKey
|
||||
public static final Key<android.hardware.camera2.params.MultiResolutionStreamConfigurationMap> SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP =
|
||||
new Key<android.hardware.camera2.params.MultiResolutionStreamConfigurationMap>("android.scaler.multiResolutionStreamConfigurationMap", android.hardware.camera2.params.MultiResolutionStreamConfigurationMap.class);
|
||||
|
||||
/**
|
||||
* <p>The area of the image sensor which corresponds to active pixels after any geometric
|
||||
* distortion correction has been applied.</p>
|
||||
|
||||
@@ -770,6 +770,8 @@ public abstract class CameraDevice implements AutoCloseable {
|
||||
* streams with {@code Y8} in all guaranteed stream combinations for the device's hardware level
|
||||
* and capabilities.</p>
|
||||
*
|
||||
* <p>Clients can access the above mandatory stream combination tables via
|
||||
* {@link android.hardware.camera2.params.MandatoryStreamCombination}.</p>
|
||||
*
|
||||
* <p>Devices capable of outputting HEIC formats ({@link StreamConfigurationMap#getOutputFormats}
|
||||
* contains {@link android.graphics.ImageFormat#HEIC}) will support substituting {@code JPEG}
|
||||
@@ -777,8 +779,33 @@ public abstract class CameraDevice implements AutoCloseable {
|
||||
* level and capabilities. Calling createCaptureSession with both JPEG and HEIC outputs is not
|
||||
* supported.</p>
|
||||
*
|
||||
* <p>Clients can access the above mandatory stream combination tables via
|
||||
* {@link android.hardware.camera2.params.MandatoryStreamCombination}.</p>
|
||||
* <p>Devices capable of multi-resolution output for a particular format (
|
||||
* {@link android.hardware.camera2.params.MultiResolutionStreamConfigurationMap#getOutputInfo}
|
||||
* returns a non-empty list) support using {@link MultiResolutionImageReader} for MAXIMUM
|
||||
* resolution streams of that format for all mandatory stream combinations. For example,
|
||||
* if a LIMITED camera device supports multi-resolution output streams for both {@code JPEG} and
|
||||
* {@code PRIVATE}, in addition to the stream configurations
|
||||
* in the LIMITED and Legacy table above, the camera device supports the following guaranteed
|
||||
* stream combinations ({@code MULTI_RES} in the Max size column refers to a {@link
|
||||
* MultiResolutionImageReader} created based on the variable max resolutions supported):
|
||||
*
|
||||
* <table>
|
||||
* <tr><th colspan="7">LEGACY-level additional guaranteed combinations with MultiResolutionoutputs</th></tr>
|
||||
* <tr> <th colspan="2" id="rb">Target 1</th> <th colspan="2" id="rb">Target 2</th> <th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
|
||||
* <tr> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th></tr>
|
||||
* <tr> <td>{@code PRIV}</td><td id="rb">{@code MULTI_RES}</td> <td colspan="2" id="rb"></td> <td colspan="2" id="rb"></td> <td>Simple preview, GPU video processing, or no-preview video recording.</td> </tr>
|
||||
* <tr> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td colspan="2" id="rb"></td> <td colspan="2" id="rb"></td> <td>No-viewfinder still image capture.</td> </tr>
|
||||
* <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td colspan="2" id="rb"></td> <td>Standard still imaging.</td> </tr>
|
||||
* <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td>Still capture plus in-app processing.</td> </tr>
|
||||
* </table><br>
|
||||
* <table>
|
||||
* <tr><th colspan="7">LIMITED-level additional guaranteed configurations with MultiResolutionoutputs</th></tr>
|
||||
* <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
|
||||
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
|
||||
* <tr> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td>Two-input in-app processing with still capture.</td> </tr>
|
||||
* </table><br>
|
||||
* The same logic applies to other hardware levels and capabilities.
|
||||
* </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
|
||||
@@ -939,6 +966,32 @@ public abstract class CameraDevice implements AutoCloseable {
|
||||
* </table><br>
|
||||
* </p>
|
||||
*
|
||||
* <p>If a camera device supports multi-resolution {@code YUV} input and multi-resolution
|
||||
* {@code YUV} output or supports multi-resolution {@code PRIVATE} input and multi-resolution
|
||||
* {@code PRIVATE} output, the additional mandatory stream combinations for LIMITED and FULL devices are listed
|
||||
* below ({@code MULTI_RES} in the Max size column refers to a
|
||||
* {@link MultiResolutionImageReader} for output, and a multi-resolution
|
||||
* {@link InputConfiguration} for input):
|
||||
* <table>
|
||||
* <tr><th colspan="11">LIMITED-level additional guaranteed configurations for creating a reprocessable capture session with multi-resolution input and multi-resolution outputs<br>({@code PRIV} input is guaranteed only if PRIVATE reprocessing is supported. {@code YUV} input is guaranteed only if YUV reprocessing is supported)</th></tr>
|
||||
* <tr><th colspan="2" id="rb">Input</th><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th rowspan="2">Sample use case(s)</th> </tr>
|
||||
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
|
||||
* <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MULTI_RES}</td> <td>Same as input</td><td id="rb">{@code MULTI_RES}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td></td><td id="rb"></td> <td></td><td id="rb"></td> <td>No-viewfinder still image reprocessing.</td> </tr>
|
||||
* <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MULTI_RES}</td> <td>Same as input</td><td id="rb">{@code MULTI_RES}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td></td><td id="rb"></td> <td>ZSL(Zero-Shutter-Lag) still imaging.</td> </tr>
|
||||
* <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MULTI_RES}</td> <td>Same as input</td><td id="rb">{@code MULTI_RES}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td></td><td id="rb"></td> <td>ZSL still and in-app processing imaging.</td> </tr>
|
||||
* <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MULTI_RES}</td> <td>Same as input</td><td id="rb">{@code MULTI_RES}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td>ZSL in-app processing with still capture.</td> </tr>
|
||||
* </table><br>
|
||||
* <table>
|
||||
* <tr><th colspan="11">FULL-level additional guaranteed configurations for creating a reprocessable capture session with multi-resolution input and multi-resolution outputs<br>({@code PRIV} input is guaranteed only if PRIVATE reprocessing is supported. {@code YUV} input is guaranteed only if YUV reprocessing is supported)</th></tr>
|
||||
* <tr><th colspan="2" id="rb">Input</th><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th rowspan="2">Sample use case(s)</th> </tr>
|
||||
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
|
||||
* <tr> <td>{@code PRIV}</td><td id="rb">{@code MULTI_RES}</td> <td>{@code PRIV}</td><td id="rb">{@code MULTI_RES}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code MULTI_RES}</td> <td></td><td id="rb"></td> <td>Maximum-resolution ZSL in-app processing with regular preview.</td> </tr>
|
||||
* <tr> <td>{@code PRIV}</td><td id="rb">{@code MULTI_RES}</td> <td>{@code PRIV}</td><td id="rb">{@code MULTI_RES}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code MULTI_RES}</td> <td></td><td id="rb"></td> <td>Maximum-resolution two-input ZSL in-app processing.</td> </tr>
|
||||
* <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MULTI_RES}</td> <td>Same as input</td><td id="rb">{@code MULTI_RES}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td>ZSL still capture and in-app processing.</td> </tr>
|
||||
* </table><br>
|
||||
* No additional mandatory stream combinations for RAW capability and LEVEL-3 hardware level.
|
||||
* </p>
|
||||
*
|
||||
* <h3>Constrained high-speed recording</h3>
|
||||
*
|
||||
* <p>The application can use a
|
||||
|
||||
@@ -31,6 +31,7 @@ import android.hardware.camera2.impl.CameraDeviceImpl;
|
||||
import android.hardware.camera2.impl.CameraMetadataNative;
|
||||
import android.hardware.camera2.params.ExtensionSessionConfiguration;
|
||||
import android.hardware.camera2.params.SessionConfiguration;
|
||||
import android.hardware.camera2.params.StreamConfiguration;
|
||||
import android.hardware.camera2.utils.CameraIdAndSessionConfiguration;
|
||||
import android.hardware.camera2.utils.ConcurrentCameraIdCombination;
|
||||
import android.hardware.display.DisplayManager;
|
||||
@@ -51,6 +52,7 @@ import android.view.Display;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
@@ -371,6 +373,47 @@ public final class CameraManager {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all physical cameras' multi-resolution stream configuration map
|
||||
*
|
||||
* <p>For a logical multi-camera, query the map between physical camera id and
|
||||
* the physical camera's multi-resolution stream configuration. This map is in turn
|
||||
* combined to form the logical camera's multi-resolution stream configuration map.</p>
|
||||
*/
|
||||
private Map<String, StreamConfiguration[]> getPhysicalCameraMultiResolutionConfigs(
|
||||
CameraMetadataNative info, ICameraService cameraService)
|
||||
throws CameraAccessException {
|
||||
HashMap<String, StreamConfiguration[]> multiResolutionStreamConfigurations =
|
||||
new HashMap<String, StreamConfiguration[]>();
|
||||
|
||||
// Query the characteristics of all physical sub-cameras, and combine the multi-resolution
|
||||
// stream configurations. Note that framework derived formats such as HEIC and DEPTH_JPEG
|
||||
// aren't supported as multi-resolution input or output formats.
|
||||
Set<String> physicalCameraIds = info.getPhysicalCameraIds();
|
||||
try {
|
||||
for (String physicalCameraId : physicalCameraIds) {
|
||||
CameraMetadataNative physicalCameraInfo =
|
||||
cameraService.getCameraCharacteristics(physicalCameraId);
|
||||
StreamConfiguration[] configs = physicalCameraInfo.get(
|
||||
CameraCharacteristics.
|
||||
SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS);
|
||||
if (configs != null) {
|
||||
multiResolutionStreamConfigurations.put(physicalCameraId, configs);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: If this is an ultra high resolution sensor camera, combine the multi-resolution
|
||||
// stream combination from "info" as well.
|
||||
} catch (RemoteException e) {
|
||||
ServiceSpecificException sse = new ServiceSpecificException(
|
||||
ICameraService.ERROR_DISCONNECTED,
|
||||
"Camera service is currently unavailable");
|
||||
throwAsPublicException(sse);
|
||||
}
|
||||
|
||||
return multiResolutionStreamConfigurations;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Query the capabilities of a camera device. These capabilities are
|
||||
* immutable for a given camera.</p>
|
||||
@@ -418,12 +461,19 @@ public final class CameraManager {
|
||||
} catch (NumberFormatException e) {
|
||||
Log.v(TAG, "Failed to parse camera Id " + cameraId + " to integer");
|
||||
}
|
||||
|
||||
boolean hasConcurrentStreams =
|
||||
CameraManagerGlobal.get().cameraIdHasConcurrentStreamsLocked(cameraId);
|
||||
info.setHasMandatoryConcurrentStreams(hasConcurrentStreams);
|
||||
info.setDisplaySize(displaySize);
|
||||
characteristics = new CameraCharacteristics(info);
|
||||
|
||||
Map<String, StreamConfiguration[]> multiResolutionSizeMap =
|
||||
getPhysicalCameraMultiResolutionConfigs(info, cameraService);
|
||||
if (multiResolutionSizeMap.size() > 0) {
|
||||
info.setMultiResolutionStreamConfigurationMap(multiResolutionSizeMap);
|
||||
}
|
||||
|
||||
characteristics = new CameraCharacteristics(info);
|
||||
} catch (ServiceSpecificException e) {
|
||||
throwAsPublicException(e);
|
||||
} catch (RemoteException e) {
|
||||
|
||||
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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;
|
||||
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.graphics.ImageFormat;
|
||||
import android.graphics.ImageFormat.Format;
|
||||
import android.hardware.HardwareBuffer;
|
||||
import android.hardware.HardwareBuffer.Usage;
|
||||
import android.media.Image;
|
||||
import android.media.ImageReader;
|
||||
import android.hardware.camera2.params.MultiResolutionStreamInfo;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
|
||||
|
||||
import java.nio.NioUtils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* <p>The MultiResolutionImageReader class wraps a group of {@link ImageReader ImageReaders} with
|
||||
* the same format and different sizes, source camera Id, or camera sensor modes.</p>
|
||||
*
|
||||
* <p>The main use case of this class is for a
|
||||
* {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA logical
|
||||
* multi-camera} or an ultra high resolution sensor camera to output variable-size images. For a
|
||||
* logical multi-camera which implements optical zoom, different physical cameras may have different
|
||||
* maximum resolutions. As a result, when the camera device switches between physical cameras
|
||||
* depending on zoom ratio, the maximum resolution for a particular format may change. For an
|
||||
* ultra high resolution sensor camera, the camera device may deem it better or worse to run in
|
||||
* maximum resolution mode / default mode depending on lighting conditions. So the application may
|
||||
* choose to let the camera device decide on its behalf.</p>
|
||||
*
|
||||
* <p>MultiResolutionImageReader should be used for a camera device only if the camera device
|
||||
* supports multi-resolution output stream by advertising the specified output format in {@link
|
||||
* CameraCharacteristics#SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP}.</p>
|
||||
*
|
||||
* <p>To acquire images from the MultiResolutionImageReader, the application must use the
|
||||
* {@link ImageReader} object passed by
|
||||
* {@link ImageReader.OnImageAvailableListener#onImageAvailable} callback to call
|
||||
* {@link ImageReader#acquireNextImage} or {@link ImageReader#acquireLatestImage}. The application
|
||||
* must not use the {@link ImageReader} passed by an {@link
|
||||
* ImageReader.OnImageAvailableListener#onImageAvailable} callback to acquire future images
|
||||
* because future images may originate from a different {@link ImageReader} contained within the
|
||||
* {@code MultiResolutionImageReader}.</p>
|
||||
*
|
||||
*
|
||||
* @see ImageReader
|
||||
* @see android.hardware.camera2.CameraCharacteristics#SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP
|
||||
*/
|
||||
public class MultiResolutionImageReader implements AutoCloseable {
|
||||
|
||||
private static final String TAG = "MultiResolutionImageReader";
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Create a new multi-resolution reader based on a group of camera stream properties returned
|
||||
* by a camera device.
|
||||
* </p>
|
||||
* <p>
|
||||
* The valid size and formats depend on the camera characteristics.
|
||||
* {@code MultiResolutionImageReader} for an image format is supported by the camera device if
|
||||
* the format is in the supported multi-resolution output stream formats returned by
|
||||
* {@link android.hardware.camera2.params.MultiResolutionStreamConfigurationMap#getOutputFormats}.
|
||||
* If the image format is supported, the {@code MultiResolutionImageReader} object can be
|
||||
* created with the {@code streams} objects returned by
|
||||
* {@link android.hardware.camera2.params.MultiResolutionStreamConfigurationMap#getOutputInfo}.
|
||||
* </p>
|
||||
* <p>
|
||||
* The {@code maxImages} parameter determines the maximum number of
|
||||
* {@link Image} objects that can be be acquired from each of the {@code ImageReader}
|
||||
* within the {@code MultiResolutionImageReader}. However, requesting more buffers will
|
||||
* use up more memory, so it is important to use only the minimum number necessary. The
|
||||
* application is strongly recommended to acquire no more than {@code maxImages} images
|
||||
* from all of the internal ImageReader objects combined. By keeping track of the number of
|
||||
* acquired images for the MultiResolutionImageReader, the application doesn't need to do the
|
||||
* bookkeeping for each internal ImageReader returned from {@link
|
||||
* ImageReader.OnImageAvailableListener#onImageAvailable onImageAvailable} callback.
|
||||
* </p>
|
||||
* <p>
|
||||
* Unlike the normal ImageReader, the MultiResolutionImageReader has a more complex
|
||||
* configuration sequence. Instead of passing the same surface to OutputConfiguration and
|
||||
* CaptureRequest, the
|
||||
* {@link android.hardware.camera2.params.OutputConfiguration#createInstancesForMultiResolutionOutput}
|
||||
* call needs to be used to create the OutputConfigurations for session creation, and then
|
||||
* {@link #getSurface} is used to get {@link CaptureRequest.Builder#addTarget the target for
|
||||
* CaptureRequest}.
|
||||
* </p>
|
||||
* @param streams The group of multi-resolution stream info, which is used to create
|
||||
* a multi-resolution reader containing a number of ImageReader objects. Each
|
||||
* ImageReader object represents a multi-resolution stream in the group.
|
||||
* @param format The format of the Image that this multi-resolution reader will produce.
|
||||
* This must be one of the {@link android.graphics.ImageFormat} or
|
||||
* {@link android.graphics.PixelFormat} constants. Note that not all formats are
|
||||
* supported, like ImageFormat.NV21. The supported multi-resolution
|
||||
* reader format can be queried by {@link
|
||||
* android.hardware.camera2.params.MultiResolutionStreamConfigurationMap#getOutputFormats}.
|
||||
* @param maxImages The maximum number of images the user will want to
|
||||
* access simultaneously. This should be as small as possible to
|
||||
* limit memory use. Once maxImages images are obtained by the
|
||||
* user from any given internal ImageReader, one of them has to be released before
|
||||
* a new Image will become available for access through the ImageReader's
|
||||
* {@link ImageReader#acquireLatestImage()} or
|
||||
* {@link ImageReader#acquireNextImage()}. Must be greater than 0.
|
||||
* @see Image
|
||||
* @see
|
||||
* android.hardware.camera2.CameraCharacteristics#SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP
|
||||
* @see
|
||||
* android.hardware.camera2.params.MultiResolutionStreamConfigurationMap
|
||||
*/
|
||||
public static @NonNull MultiResolutionImageReader newInstance(
|
||||
@NonNull Collection<MultiResolutionStreamInfo> streams,
|
||||
@Format int format,
|
||||
@IntRange(from = 1) int maxImages) {
|
||||
return new MultiResolutionImageReader(streams, format, maxImages);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
protected MultiResolutionImageReader(Collection<MultiResolutionStreamInfo> streams,
|
||||
int format, int maxImages) {
|
||||
mFormat = format;
|
||||
mMaxImages = maxImages;
|
||||
|
||||
if (streams == null || streams.size() <= 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"The streams info collection must contain at least 2 entries");
|
||||
}
|
||||
if (mMaxImages < 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"Maximum outstanding image count must be at least 1");
|
||||
}
|
||||
|
||||
if (format == ImageFormat.NV21) {
|
||||
throw new IllegalArgumentException(
|
||||
"NV21 format is not supported");
|
||||
}
|
||||
|
||||
int numImageReaders = streams.size();
|
||||
mReaders = new ImageReader[numImageReaders];
|
||||
mStreamInfo = new MultiResolutionStreamInfo[numImageReaders];
|
||||
int index = 0;
|
||||
for (MultiResolutionStreamInfo streamInfo : streams) {
|
||||
mReaders[index] = ImageReader.newInstance(streamInfo.getWidth(),
|
||||
streamInfo.getHeight(), format, maxImages);
|
||||
mStreamInfo[index] = streamInfo;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set onImageAvailableListener callback.
|
||||
*
|
||||
* <p>This function sets the onImageAvailableListener for all the internal
|
||||
* {@link ImageReader} objects.</p>
|
||||
*
|
||||
* <p>For a multi-resolution ImageReader, the timestamps of images acquired in
|
||||
* onImageAvailable callback from different internal ImageReaders may become
|
||||
* out-of-order due to the asynchronous callbacks between the different resolution
|
||||
* image queues.</p>
|
||||
*
|
||||
* @param listener
|
||||
* The listener that will be run.
|
||||
* @param executor
|
||||
* The executor which will be used when invoking the callback.
|
||||
*/
|
||||
@SuppressLint({"ExecutorRegistration", "SamShouldBeLast"})
|
||||
public void setOnImageAvailableListener(
|
||||
@Nullable ImageReader.OnImageAvailableListener listener,
|
||||
@Nullable @CallbackExecutor Executor executor) {
|
||||
for (int i = 0; i < mReaders.length; i++) {
|
||||
mReaders[i].setOnImageAvailableListenerWithExecutor(listener, executor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
flush();
|
||||
|
||||
for (int i = 0; i < mReaders.length; i++) {
|
||||
mReaders[i].close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() {
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush pending images from all internal ImageReaders
|
||||
*
|
||||
* <p>Acquire and close pending images from all internal ImageReaders. This has the same
|
||||
* effect as calling acquireLatestImage() on all internal ImageReaders, and closing all
|
||||
* latest images.</p>
|
||||
*/
|
||||
public void flush() {
|
||||
flushOther(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush pending images from other internal ImageReaders
|
||||
*
|
||||
* <p>Acquire and close pending images from all internal ImageReaders except for the
|
||||
* one specified.</p>
|
||||
*
|
||||
* @param reader The ImageReader object that won't be flushed.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void flushOther(ImageReader reader) {
|
||||
for (int i = 0; i < mReaders.length; i++) {
|
||||
if (reader != null && reader == mReaders[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
Image image = mReaders[i].acquireNextImageNoThrowISE();
|
||||
if (image == null) {
|
||||
break;
|
||||
} else {
|
||||
image.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internal ImageReader objects
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public @NonNull ImageReader[] getReaders() {
|
||||
return mReaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the surface that is used as a target for {@link CaptureRequest}
|
||||
*
|
||||
* <p>The application must use the surface returned by this function as a target for
|
||||
* {@link CaptureRequest}. The camera device makes the decision on which internal
|
||||
* {@code ImageReader} will receive the output image.</p>
|
||||
*
|
||||
* <p>Please note that holding on to the Surface objects returned by this method is not enough
|
||||
* to keep their parent MultiResolutionImageReaders from being reclaimed. In that sense, a
|
||||
* Surface acts like a {@link java.lang.ref.WeakReference weak reference} to the
|
||||
* MultiResolutionImageReader that provides it.</p>
|
||||
*
|
||||
* @return a {@link Surface} to use as the target for a capture request.
|
||||
*/
|
||||
public @NonNull Surface getSurface() {
|
||||
//TODO: Pick the surface from the reader for default mode stream.
|
||||
return mReaders[0].getSurface();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the MultiResolutionStreamInfo describing the ImageReader an image originates from
|
||||
*
|
||||
*<p>An image from a {@code MultiResolutionImageReader} is produced from one of the underlying
|
||||
*{@code ImageReader}s. This function returns the {@link MultiResolutionStreamInfo} to describe
|
||||
*the property for that {@code ImageReader}, such as width, height, and physical camera Id.</p>
|
||||
*
|
||||
* @param reader An internal ImageReader within {@code MultiResolutionImageReader}.
|
||||
*
|
||||
* @return The stream info describing the internal {@code ImageReader}.
|
||||
*/
|
||||
public @NonNull MultiResolutionStreamInfo getStreamInfoForImageReader(
|
||||
@NonNull ImageReader reader) {
|
||||
for (int i = 0; i < mReaders.length; i++) {
|
||||
if (reader == mReaders[i]) {
|
||||
return mStreamInfo[i];
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("ImageReader doesn't belong to this multi-resolution "
|
||||
+ "imagereader");
|
||||
}
|
||||
|
||||
// mReaders and mStreamInfo has the same length, and their entries are 1:1 mapped.
|
||||
private final ImageReader[] mReaders;
|
||||
private final MultiResolutionStreamInfo[] mStreamInfo;
|
||||
|
||||
private final int mFormat;
|
||||
private final int mMaxImages;
|
||||
}
|
||||
@@ -61,8 +61,8 @@ public final class TotalCaptureResult extends CaptureResult {
|
||||
|
||||
private final List<CaptureResult> mPartialResults;
|
||||
private final int mSessionId;
|
||||
// The map between physical camera id and capture result
|
||||
private final HashMap<String, CaptureResult> mPhysicalCaptureResults;
|
||||
// The map between physical camera ids and their total capture result
|
||||
private final HashMap<String, TotalCaptureResult> mPhysicalCaptureResults;
|
||||
|
||||
/**
|
||||
* Takes ownership of the passed-in camera metadata and the partial results
|
||||
@@ -83,10 +83,11 @@ public final class TotalCaptureResult extends CaptureResult {
|
||||
|
||||
mSessionId = sessionId;
|
||||
|
||||
mPhysicalCaptureResults = new HashMap<String, CaptureResult>();
|
||||
mPhysicalCaptureResults = new HashMap<String, TotalCaptureResult>();
|
||||
for (PhysicalCaptureResultInfo onePhysicalResult : physicalResults) {
|
||||
CaptureResult physicalResult = new CaptureResult(onePhysicalResult.getCameraId(),
|
||||
onePhysicalResult.getCameraMetadata(), parent, extras);
|
||||
TotalCaptureResult physicalResult = new TotalCaptureResult(
|
||||
onePhysicalResult.getCameraId(), onePhysicalResult.getCameraMetadata(),
|
||||
parent, extras, /*partials*/null, sessionId, new PhysicalCaptureResultInfo[0]);
|
||||
mPhysicalCaptureResults.put(onePhysicalResult.getCameraId(),
|
||||
physicalResult);
|
||||
}
|
||||
@@ -103,7 +104,7 @@ public final class TotalCaptureResult extends CaptureResult {
|
||||
|
||||
mPartialResults = new ArrayList<>();
|
||||
mSessionId = CameraCaptureSession.SESSION_ID_NONE;
|
||||
mPhysicalCaptureResults = new HashMap<String, CaptureResult>();
|
||||
mPhysicalCaptureResults = new HashMap<String, TotalCaptureResult>();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,8 +147,37 @@ public final class TotalCaptureResult extends CaptureResult {
|
||||
* cameras. Otherwise, an empty map is returned.</p>
|
||||
|
||||
* @return unmodifiable map between physical camera ids and their capture result metadata
|
||||
*
|
||||
* @deprecated
|
||||
* <p>Please use {@link #getPhysicalCameraTotalResults() instead to get the
|
||||
* physical cameras' {@code TotalCaptureResult}.</p>
|
||||
*/
|
||||
public Map<String, CaptureResult> getPhysicalCameraResults() {
|
||||
return Collections.unmodifiableMap(mPhysicalCaptureResults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the map between physical camera ids and their total capture result metadata
|
||||
*
|
||||
* <p>This function can be called for logical multi-camera devices, which are devices that have
|
||||
* REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA capability.</p>
|
||||
*
|
||||
* <p>If one or more streams from the underlying physical cameras were requested by the
|
||||
* corresponding capture request, this function returns the total result metadata for those
|
||||
* physical cameras. Otherwise, an empty map is returned.</p>
|
||||
*
|
||||
* <p>This function replaces the deprecated {@link #getPhysicalCameraResults}, and its return
|
||||
* value is a map of TotalCaptureResult rather than CaptureResult. </p>
|
||||
*
|
||||
* <p>To reprocess an image from a physical camera stream, typically returned from a
|
||||
* {@link MultiResolutionImageReader}, the application must look up this map to get the {@link
|
||||
* TotalCaptureResult} from the physical camera and pass it to {@link
|
||||
* CameraDevice#createReprocessCaptureRequest}.</p>
|
||||
*
|
||||
* @return unmodifiable map between physical camera ids and their total capture result metadata
|
||||
*/
|
||||
@NonNull
|
||||
public Map<String, TotalCaptureResult> getPhysicalCameraTotalResults() {
|
||||
return Collections.unmodifiableMap(mPhysicalCaptureResults);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ import android.hardware.camera2.ICameraOfflineSession;
|
||||
import android.hardware.camera2.TotalCaptureResult;
|
||||
import android.hardware.camera2.params.ExtensionSessionConfiguration;
|
||||
import android.hardware.camera2.params.InputConfiguration;
|
||||
import android.hardware.camera2.params.MultiResolutionStreamConfigurationMap;
|
||||
import android.hardware.camera2.params.MultiResolutionStreamInfo;
|
||||
import android.hardware.camera2.params.OutputConfiguration;
|
||||
import android.hardware.camera2.params.SessionConfiguration;
|
||||
import android.hardware.camera2.params.StreamConfigurationMap;
|
||||
@@ -468,7 +470,8 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
}
|
||||
if (inputConfig != null) {
|
||||
int streamId = mRemoteDevice.createInputStream(inputConfig.getWidth(),
|
||||
inputConfig.getHeight(), inputConfig.getFormat());
|
||||
inputConfig.getHeight(), inputConfig.getFormat(),
|
||||
inputConfig.isMultiResolution());
|
||||
mConfiguredInput = new SimpleEntry<Integer, InputConfiguration>(
|
||||
streamId, inputConfig);
|
||||
}
|
||||
@@ -1355,7 +1358,42 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
}
|
||||
|
||||
private void checkInputConfiguration(InputConfiguration inputConfig) {
|
||||
if (inputConfig != null) {
|
||||
if (inputConfig == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (inputConfig.isMultiResolution()) {
|
||||
MultiResolutionStreamConfigurationMap configMap = mCharacteristics.get(
|
||||
CameraCharacteristics.SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP);
|
||||
|
||||
int[] inputFormats = configMap.getInputFormats();
|
||||
boolean validFormat = false;
|
||||
for (int format : inputFormats) {
|
||||
if (format == inputConfig.getFormat()) {
|
||||
validFormat = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (validFormat == false) {
|
||||
throw new IllegalArgumentException("multi-resolution input format " +
|
||||
inputConfig.getFormat() + " is not valid");
|
||||
}
|
||||
|
||||
boolean validSize = false;
|
||||
Collection<MultiResolutionStreamInfo> inputStreamInfo =
|
||||
configMap.getInputInfo(inputConfig.getFormat());
|
||||
for (MultiResolutionStreamInfo info : inputStreamInfo) {
|
||||
if (inputConfig.getWidth() == info.getWidth() &&
|
||||
inputConfig.getHeight() == info.getHeight()) {
|
||||
validSize = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (validSize == false) {
|
||||
throw new IllegalArgumentException("Multi-resolution input size " +
|
||||
inputConfig.getWidth() + "x" + inputConfig.getHeight() + " is not valid");
|
||||
}
|
||||
} else {
|
||||
StreamConfigurationMap configMap = mCharacteristics.get(
|
||||
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.hardware.camera2.impl;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.graphics.ImageFormat;
|
||||
import android.graphics.Point;
|
||||
@@ -53,6 +54,7 @@ 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.MultiResolutionStreamConfigurationMap;
|
||||
import android.hardware.camera2.params.OisSample;
|
||||
import android.hardware.camera2.params.RecommendedStreamConfiguration;
|
||||
import android.hardware.camera2.params.RecommendedStreamConfigurationMap;
|
||||
@@ -61,6 +63,7 @@ import android.hardware.camera2.params.StreamConfiguration;
|
||||
import android.hardware.camera2.params.StreamConfigurationDuration;
|
||||
import android.hardware.camera2.params.StreamConfigurationMap;
|
||||
import android.hardware.camera2.params.TonemapCurve;
|
||||
import android.hardware.camera2.utils.ArrayUtils;
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
@@ -79,9 +82,14 @@ import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Implementation of camera metadata marshal/unmarshal across Binder to
|
||||
@@ -747,6 +755,15 @@ public class CameraMetadataNative implements Parcelable {
|
||||
return (T) metadata.getExtendedSceneModeCapabilities();
|
||||
}
|
||||
});
|
||||
sGetCommandMap.put(
|
||||
CameraCharacteristics.SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP.getNativeKey(),
|
||||
new GetCommand() {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
|
||||
return (T) metadata.getMultiResolutionStreamConfigurationMap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private int[] getAvailableFormats() {
|
||||
@@ -1688,6 +1705,7 @@ public class CameraMetadataNative implements Parcelable {
|
||||
private boolean mHasMandatoryConcurrentStreams = false;
|
||||
private Size mDisplaySize = new Size(0, 0);
|
||||
private long mBufferSize = 0;
|
||||
private MultiResolutionStreamConfigurationMap mMultiResolutionStreamConfigurationMap = null;
|
||||
|
||||
/**
|
||||
* Set the current camera Id.
|
||||
@@ -1723,6 +1741,30 @@ public class CameraMetadataNative implements Parcelable {
|
||||
mDisplaySize = displaySize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the multi-resolution stream configuration map.
|
||||
*
|
||||
* @param multiResolutionMap The multi-resolution stream configuration map.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void setMultiResolutionStreamConfigurationMap(
|
||||
@NonNull Map<String, StreamConfiguration[]> multiResolutionMap) {
|
||||
mMultiResolutionStreamConfigurationMap =
|
||||
new MultiResolutionStreamConfigurationMap(multiResolutionMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the multi-resolution stream configuration map.
|
||||
*
|
||||
* @return The multi-resolution stream configuration map.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public MultiResolutionStreamConfigurationMap getMultiResolutionStreamConfigurationMap() {
|
||||
return mMultiResolutionStreamConfigurationMap;
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
private long mMetadataPtr; // native std::shared_ptr<CameraMetadata>*
|
||||
|
||||
@@ -1777,6 +1819,7 @@ public class CameraMetadataNative implements Parcelable {
|
||||
mCameraId = other.mCameraId;
|
||||
mHasMandatoryConcurrentStreams = other.mHasMandatoryConcurrentStreams;
|
||||
mDisplaySize = other.mDisplaySize;
|
||||
mMultiResolutionStreamConfigurationMap = other.mMultiResolutionStreamConfigurationMap;
|
||||
updateNativeAllocation();
|
||||
other.updateNativeAllocation();
|
||||
}
|
||||
@@ -1980,6 +2023,39 @@ public class CameraMetadataNative implements Parcelable {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the set of physical camera ids that this logical {@link CameraDevice} is made
|
||||
* up of.
|
||||
*
|
||||
* If the camera device isn't a logical camera, return an empty set.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public Set<String> getPhysicalCameraIds() {
|
||||
int[] availableCapabilities = get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
|
||||
if (availableCapabilities == null) {
|
||||
throw new AssertionError("android.request.availableCapabilities must be non-null "
|
||||
+ "in the characteristics");
|
||||
}
|
||||
|
||||
if (!ArrayUtils.contains(availableCapabilities,
|
||||
CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
byte[] physicalCamIds = get(CameraCharacteristics.LOGICAL_MULTI_CAMERA_PHYSICAL_IDS);
|
||||
|
||||
String physicalCamIdString = null;
|
||||
try {
|
||||
physicalCamIdString = new String(physicalCamIds, "UTF-8");
|
||||
} catch (java.io.UnsupportedEncodingException e) {
|
||||
throw new AssertionError("android.logicalCam.physicalIds must be UTF-8 string");
|
||||
}
|
||||
String[] physicalCameraIdArray = physicalCamIdString.split("\0");
|
||||
|
||||
return Collections.unmodifiableSet(
|
||||
new HashSet<String>(Arrays.asList(physicalCameraIdArray)));
|
||||
}
|
||||
|
||||
static {
|
||||
registerAllMarshalers();
|
||||
}
|
||||
|
||||
@@ -140,9 +140,10 @@ public class ICameraDeviceUserWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
public int createInputStream(int width, int height, int format) throws CameraAccessException {
|
||||
public int createInputStream(int width, int height, int format, boolean isMultiResolution)
|
||||
throws CameraAccessException {
|
||||
try {
|
||||
return mRemoteDevice.createInputStream(width, height, format);
|
||||
return mRemoteDevice.createInputStream(width, height, format, isMultiResolution);
|
||||
} catch (Throwable t) {
|
||||
CameraManager.throwAsPublicException(t);
|
||||
throw new UnsupportedOperationException("Unexpected exception", t);
|
||||
|
||||
@@ -16,9 +16,17 @@
|
||||
|
||||
package android.hardware.camera2.params;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.graphics.ImageFormat.Format;
|
||||
import android.hardware.camera2.params.MultiResolutionStreamInfo;
|
||||
import android.hardware.camera2.utils.HashCodeHelpers;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
|
||||
/**
|
||||
* Immutable class to store an input configuration that is used to create a reprocessable capture
|
||||
* session.
|
||||
@@ -31,11 +39,12 @@ public final class InputConfiguration {
|
||||
private final int mWidth;
|
||||
private final int mHeight;
|
||||
private final int mFormat;
|
||||
private final boolean mIsMultiResolution;
|
||||
|
||||
/**
|
||||
* Create an input configration with the width, height, and user-defined format.
|
||||
*
|
||||
* <p>Images of an user-defined format are accessible by applications. Use
|
||||
* <p>Images of a user-defined format are accessible by applications. Use
|
||||
* {@link android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP}
|
||||
* to query supported input formats</p>
|
||||
*
|
||||
@@ -51,6 +60,52 @@ public final class InputConfiguration {
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
mFormat = format;
|
||||
mIsMultiResolution = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an input configration with the format and a list of multi-resolution input stream
|
||||
* info.
|
||||
*
|
||||
* <p>Use {@link
|
||||
* android.hardware.camera2.CameraCharacteristics#SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP}
|
||||
* to query supported multi-resolution input formats.</p>
|
||||
*
|
||||
* <p>To do reprocessing with variable resolution input, the application calls
|
||||
* {@link android.media.ImageWriter#queueInputImage ImageWriter.queueInputImage}
|
||||
* using an image from an {@link android.media.ImageReader ImageReader} or {@link
|
||||
* android.hardware.camera2.MultiResolutionImageReader MultiResolutionImageReader}. See
|
||||
* {@link android.hardware.camera2.CameraDevice#createReprocessCaptureRequest} for more
|
||||
* details on camera reprocessing.
|
||||
* </p>
|
||||
*
|
||||
* @param multiResolutionInputs A group of multi-resolution input info for the specified format.
|
||||
* @param format Format of the input buffers. One of ImageFormat or PixelFormat constants.
|
||||
*
|
||||
* @see android.graphics.ImageFormat
|
||||
* @see android.graphics.PixelFormat
|
||||
* @see
|
||||
* android.hardware.camera2.CameraCharacteristics#SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP
|
||||
*/
|
||||
public InputConfiguration(@NonNull Collection<MultiResolutionStreamInfo> multiResolutionInputs,
|
||||
@Format int format) {
|
||||
checkCollectionNotEmpty(multiResolutionInputs, "Input multi-resolution stream info");
|
||||
//TODO: Pick the default mode stream info for ultra-high resolution sensor camera
|
||||
MultiResolutionStreamInfo info = multiResolutionInputs.iterator().next();
|
||||
mWidth = info.getWidth();
|
||||
mHeight = info.getHeight();
|
||||
mFormat = format;
|
||||
mIsMultiResolution = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public InputConfiguration(int width, int height, int format, boolean isMultiResolution) {
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
mFormat = format;
|
||||
mIsMultiResolution = isMultiResolution;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,6 +135,18 @@ public final class InputConfiguration {
|
||||
return mFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this input configuration is of multi-resolution.
|
||||
*
|
||||
* <p>An multi-resolution InputConfiguration means that the reprocessing session created from it
|
||||
* allows input images of different sizes.</p>
|
||||
*
|
||||
* @return this input configuration is multi-resolution or not.
|
||||
*/
|
||||
public boolean isMultiResolution() {
|
||||
return mIsMultiResolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this InputConfiguration is equal to another InputConfiguration.
|
||||
*
|
||||
@@ -100,7 +167,8 @@ public final class InputConfiguration {
|
||||
|
||||
if (otherInputConfig.getWidth() == mWidth &&
|
||||
otherInputConfig.getHeight() == mHeight &&
|
||||
otherInputConfig.getFormat() == mFormat) {
|
||||
otherInputConfig.getFormat() == mFormat &&
|
||||
otherInputConfig.isMultiResolution() == mIsMultiResolution) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -111,19 +179,21 @@ public final class InputConfiguration {
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return HashCodeHelpers.hashCode(mWidth, mHeight, mFormat);
|
||||
return HashCodeHelpers.hashCode(mWidth, mHeight, mFormat, mIsMultiResolution ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this {@link InputConfiguration} as a string representation.
|
||||
*
|
||||
* <p> {@code "InputConfiguration(w:%d, h:%d, format:%d)"}, where {@code %d} represents
|
||||
* the width, height, and format, respectively.</p>
|
||||
* <p> {@code "InputConfiguration(w:%d, h:%d, format:%d, isMultiResolution:%d)"},
|
||||
* where {@code %d} represents the width, height, format, and multi-resolution flag
|
||||
* respectively.</p>
|
||||
*
|
||||
* @return string representation of {@link InputConfiguration}
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("InputConfiguration(w:%d, h:%d, format:%d)", mWidth, mHeight, mFormat);
|
||||
return String.format("InputConfiguration(w:%d, h:%d, format:%d, isMultiResolution %b)",
|
||||
mWidth, mHeight, mFormat, mIsMultiResolution);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1296,19 +1296,6 @@ public final class MandatoryStreamCombination {
|
||||
return kPreviewSizeBound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Size comparison method used by size comparators.
|
||||
*/
|
||||
private static int compareSizes(int widthA, int heightA, int widthB, int heightB) {
|
||||
long left = widthA * (long) heightA;
|
||||
long right = widthB * (long) heightB;
|
||||
if (left == right) {
|
||||
left = widthA;
|
||||
right = widthB;
|
||||
}
|
||||
return (left < right) ? -1 : (left > right ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Size comparator that compares the number of pixels it covers.
|
||||
*
|
||||
@@ -1317,8 +1304,8 @@ public final class MandatoryStreamCombination {
|
||||
public static class SizeComparator implements Comparator<Size> {
|
||||
@Override
|
||||
public int compare(@NonNull Size lhs, @NonNull Size rhs) {
|
||||
return compareSizes(lhs.getWidth(), lhs.getHeight(), rhs.getWidth(),
|
||||
rhs.getHeight());
|
||||
return StreamConfigurationMap.compareSizes(lhs.getWidth(), lhs.getHeight(),
|
||||
rhs.getWidth(), rhs.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.params;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
|
||||
import android.graphics.ImageFormat;
|
||||
import android.graphics.ImageFormat.Format;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.hardware.camera2.params.MultiResolutionStreamInfo;
|
||||
import android.hardware.camera2.params.StreamConfigurationMap;
|
||||
import android.hardware.camera2.utils.HashCodeHelpers;
|
||||
|
||||
import android.util.Size;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
|
||||
/**
|
||||
* Immutable class to store the information of the multi-resolution streams supported by
|
||||
* the camera device.
|
||||
*
|
||||
* <p>For a {@link
|
||||
* android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
|
||||
* logical multi-camera} or an ultra high resolution sensor camera, the maximum resolution of images
|
||||
* produced by the camera device may be variable. For example, for a logical multi-camera, depending
|
||||
* on factors such as current zoom ratio, the camera device may be backed by different physical
|
||||
* cameras. If the physical cameras are of different resolutions, the application may intend to
|
||||
* consume the variable full resolution images from the physical cameras. For an ultra high
|
||||
* resolution sensor camera, the same use case exists where depending on lighting conditions, the
|
||||
* camera device may deem it better to run in default mode and maximum resolution mode.
|
||||
* </p>
|
||||
*
|
||||
* <p>For the use cases described above, multi-resolution output streams can be used by
|
||||
* {@link android.hardware.camera2.MultiResolutionImageReader} to allow the
|
||||
* camera device to output variable size maximum-resolution images.</p>
|
||||
*
|
||||
* <p>Similarly, multi-resolution input streams can be used for reprocessing of variable size
|
||||
* images. In order to reprocess input images of different sizes, the {@link InputConfiguration}
|
||||
* used for creating reprocessable session can be initialized using the group of input stream
|
||||
* configurations returned by {@link #getInputInfo}.</p>
|
||||
*/
|
||||
public final class MultiResolutionStreamConfigurationMap {
|
||||
/**
|
||||
* Create a new {@link MultiResolutionStreamConfigurationMap}.
|
||||
*
|
||||
* @param configurations a non-{@code null} array of multi-resolution stream
|
||||
* configurations supported by this camera device
|
||||
* @hide
|
||||
*/
|
||||
public MultiResolutionStreamConfigurationMap(
|
||||
@NonNull Map<String, StreamConfiguration[]> configurations) {
|
||||
checkNotNull(configurations, "multi-resolution configurations must not be null");
|
||||
if (configurations.size() == 0) {
|
||||
throw new IllegalArgumentException("multi-resolution configurations must not be empty");
|
||||
}
|
||||
|
||||
mConfigurations = configurations;
|
||||
|
||||
// For each multi-resolution stream configuration, track how many formats and sizes there
|
||||
// are available to configure
|
||||
for (Map.Entry<String, StreamConfiguration[]> entry :
|
||||
mConfigurations.entrySet()) {
|
||||
String cameraId = entry.getKey();
|
||||
StreamConfiguration[] configs = entry.getValue();
|
||||
|
||||
for (int i = 0; i < configs.length; i++) {
|
||||
StreamConfiguration config = configs[i];
|
||||
int format = config.getFormat();
|
||||
|
||||
MultiResolutionStreamInfo multiResolutionStreamInfo = new MultiResolutionStreamInfo(
|
||||
config.getWidth(), config.getHeight(), cameraId);
|
||||
Map<Integer, List<MultiResolutionStreamInfo>> destMap;
|
||||
if (config.isInput()) {
|
||||
destMap = mMultiResolutionInputConfigs;
|
||||
} else {
|
||||
destMap = mMultiResolutionOutputConfigs;
|
||||
}
|
||||
|
||||
if (!destMap.containsKey(format)) {
|
||||
List<MultiResolutionStreamInfo> multiResolutionStreamInfoList =
|
||||
new ArrayList<MultiResolutionStreamInfo>();
|
||||
destMap.put(format, multiResolutionStreamInfoList);
|
||||
}
|
||||
destMap.get(format).add(multiResolutionStreamInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Size comparator that compares the number of pixels two MultiResolutionStreamInfo size covers.
|
||||
*
|
||||
* <p>If two the areas of two sizes are same, compare the widths.</p>
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static class SizeComparator implements Comparator<MultiResolutionStreamInfo> {
|
||||
@Override
|
||||
public int compare(@NonNull MultiResolutionStreamInfo lhs,
|
||||
@NonNull MultiResolutionStreamInfo rhs) {
|
||||
return StreamConfigurationMap.compareSizes(
|
||||
lhs.getWidth(), lhs.getHeight(), rhs.getWidth(), rhs.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the output formats in this multi-resolution stream configuration.
|
||||
*
|
||||
* <p>A logical multi-camera or an ultra high resolution sensor camera may support
|
||||
* {@link android.hardware.camera2.MultiResolutionImageReader} to dynamically output maximum
|
||||
* resolutions of different sizes (when switching between physical cameras, or between different
|
||||
* modes of an ultra high resolution sensor camera). This function returns the formats
|
||||
* supported for such case.</p>
|
||||
*
|
||||
* <p>All image formats returned by this function will be defined in either {@link ImageFormat}
|
||||
* or in {@link PixelFormat} (and there is no possibility of collision).</p>
|
||||
*
|
||||
* @return an array of integer format, or empty array if multi-resolution output is not
|
||||
* supported
|
||||
*
|
||||
* @see ImageFormat
|
||||
* @see PixelFormat
|
||||
* @see android.hardware.camera2.MultiResolutionImageReader
|
||||
*/
|
||||
public @NonNull @Format int[] getOutputFormats() {
|
||||
return getPublicImageFormats(/*output*/true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the input formats in this multi-resolution stream configuration.
|
||||
*
|
||||
* <p>A logical multi-camera or ultra high resolution sensor camera may support reprocessing
|
||||
* images of different resolutions when switching between physical cameras, or between
|
||||
* different modes of the ultra high resolution sensor camera. This function returns the
|
||||
* formats supported for such case.</p>
|
||||
*
|
||||
* <p>The supported output format for an input format can be queried by calling the camera
|
||||
* device's {@link StreamConfigurationMap#getValidOutputFormatsForInput}.</p>
|
||||
*
|
||||
* <p>All image formats returned by this function will be defined in either {@link ImageFormat}
|
||||
* or in {@link PixelFormat} (and there is no possibility of collision).</p>
|
||||
*
|
||||
* @return an array of integer format, or empty array if no multi-resolution reprocessing is
|
||||
* supported
|
||||
*
|
||||
* @see ImageFormat
|
||||
* @see PixelFormat
|
||||
*/
|
||||
public @NonNull @Format int[] getInputFormats() {
|
||||
return getPublicImageFormats(/*output*/false);
|
||||
}
|
||||
|
||||
// Get the list of publicly visible multi-resolution input/output stream formats
|
||||
private int[] getPublicImageFormats(boolean output) {
|
||||
Map<Integer, List<MultiResolutionStreamInfo>> multiResolutionConfigs =
|
||||
output ? mMultiResolutionOutputConfigs : mMultiResolutionInputConfigs;
|
||||
int formatCount = multiResolutionConfigs.size();
|
||||
|
||||
int[] formats = new int[formatCount];
|
||||
int i = 0;
|
||||
for (Integer format : multiResolutionConfigs.keySet()) {
|
||||
formats[i++] = StreamConfigurationMap.imageFormatToPublic(format);
|
||||
}
|
||||
|
||||
return formats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a group of {@code MultiResolutionStreamInfo} with the requested output image
|
||||
* {@code format}
|
||||
*
|
||||
* <p>The {@code format} should be a supported format (one of the formats returned by
|
||||
* {@link #getOutputFormats}).</p>
|
||||
*
|
||||
* @param format an image format from {@link ImageFormat} or {@link PixelFormat}
|
||||
* @return
|
||||
* a group of supported {@link MultiResolutionStreamInfo}. If the {@code format} is not
|
||||
* a supported multi-resolution output, an empty group is returned.
|
||||
*
|
||||
* @see ImageFormat
|
||||
* @see PixelFormat
|
||||
* @see #getOutputFormats
|
||||
*/
|
||||
public @NonNull Collection<MultiResolutionStreamInfo> getOutputInfo(@Format int format) {
|
||||
return getInfo(format, /*false*/ true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a group of {@code MultiResolutionStreamInfo} with the requested input image {@code format}
|
||||
*
|
||||
* <p>The {@code format} should be a supported format (one of the formats returned by
|
||||
* {@link #getInputFormats}).</p>
|
||||
*
|
||||
* @param format an image format from {@link ImageFormat} or {@link PixelFormat}
|
||||
* @return
|
||||
* a group of supported {@link MultiResolutionStreamInfo}. If the {@code format} is not
|
||||
* a supported multi-resolution input, an empty group is returned.
|
||||
*
|
||||
* @see ImageFormat
|
||||
* @see PixelFormat
|
||||
* @see #getInputFormats
|
||||
*/
|
||||
public @NonNull Collection<MultiResolutionStreamInfo> getInputInfo(@Format int format) {
|
||||
return getInfo(format, /*false*/ false);
|
||||
}
|
||||
|
||||
// Get multi-resolution stream info for a particular format
|
||||
private @NonNull Collection<MultiResolutionStreamInfo> getInfo(int format, boolean output) {
|
||||
int internalFormat = StreamConfigurationMap.imageFormatToInternal(format);
|
||||
Map<Integer, List<MultiResolutionStreamInfo>> multiResolutionConfigs =
|
||||
output ? mMultiResolutionOutputConfigs : mMultiResolutionInputConfigs;
|
||||
if (multiResolutionConfigs.containsKey(internalFormat)) {
|
||||
return Collections.unmodifiableCollection(multiResolutionConfigs.get(internalFormat));
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
private void appendConfigurationsString(StringBuilder sb, boolean output) {
|
||||
sb.append(output ? "Outputs(" : "Inputs(");
|
||||
int[] formats = getPublicImageFormats(output);
|
||||
if (formats != null) {
|
||||
for (int format : formats) {
|
||||
Collection<MultiResolutionStreamInfo> streamInfoList =
|
||||
getInfo(format, output);
|
||||
sb.append("[" + StreamConfigurationMap.formatToString(format) + ":");
|
||||
for (MultiResolutionStreamInfo streamInfo : streamInfoList) {
|
||||
sb.append(String.format("[w:%d, h:%d, id:%s], ",
|
||||
streamInfo.getWidth(), streamInfo.getHeight(),
|
||||
streamInfo.getPhysicalCameraId()));
|
||||
}
|
||||
// Remove the pending ", "
|
||||
if (sb.charAt(sb.length() - 1) == ' ') {
|
||||
sb.delete(sb.length() - 2, sb.length());
|
||||
}
|
||||
sb.append("]");
|
||||
}
|
||||
}
|
||||
sb.append(")");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this {@link MultiResolutionStreamConfigurationMap} is equal to another
|
||||
* {@link MultiResolutionStreamConfigurationMap}.
|
||||
*
|
||||
* @return {@code true} if the objects were equal, {@code false} otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof MultiResolutionStreamConfigurationMap) {
|
||||
final MultiResolutionStreamConfigurationMap other =
|
||||
(MultiResolutionStreamConfigurationMap) obj;
|
||||
if (!mConfigurations.keySet().equals(other.mConfigurations.keySet())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (String id : mConfigurations.keySet()) {
|
||||
if (!Arrays.equals(mConfigurations.get(id), other.mConfigurations.get(id))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return HashCodeHelpers.hashCodeGeneric(
|
||||
mConfigurations, mMultiResolutionOutputConfigs, mMultiResolutionInputConfigs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this {@link MultiResolutionStreamConfigurationMap} as a string representation.
|
||||
*
|
||||
* <p>{@code "MultiResolutionStreamConfigurationMap(Outputs([format1: [w:%d, h:%d, id:%s], ...
|
||||
* ... [w:%d, h:%d, id:%s]), [format2: [w:%d, h:%d, id:%s], ... [w:%d, h:%d, id:%s]], ...),
|
||||
* Inputs([format1: [w:%d, h:%d, id:%s], ... [w:%d, h:%d, id:%s], ...).</p>
|
||||
*
|
||||
* @return string representation of {@link MultiResolutionStreamConfigurationMap}
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("MultiResolutionStreamConfigurationMap(");
|
||||
appendConfigurationsString(sb, /*output*/ true);
|
||||
sb.append(",");
|
||||
appendConfigurationsString(sb, /*output*/ false);
|
||||
sb.append(")");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
private final Map<String, StreamConfiguration[]> mConfigurations;
|
||||
|
||||
/** Format -> list of MultiResolutionStreamInfo used to create MultiResolutionImageReader */
|
||||
private final Map<Integer, List<MultiResolutionStreamInfo>> mMultiResolutionOutputConfigs
|
||||
= new HashMap<Integer, List<MultiResolutionStreamInfo>>();
|
||||
/** Format -> list of MultiResolutionStreamInfo used for multi-resolution reprocessing */
|
||||
private final Map<Integer, List<MultiResolutionStreamInfo>> mMultiResolutionInputConfigs
|
||||
= new HashMap<Integer, List<MultiResolutionStreamInfo>>();
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.params;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A utility class describing the properties of one stream of fixed-size image buffers
|
||||
* backing a multi-resolution image stream.
|
||||
*
|
||||
* <p>A group of {@link MultiResolutionStreamInfo} are used to describe the properties of a
|
||||
* multi-resolution image stream for a particular format. The
|
||||
* {@link android.hardware.camera2.MultiResolutionImageReader} class represents a
|
||||
* multi-resolution output stream, and is constructed using a group of
|
||||
* {@link MultiResolutionStreamInfo}. A group of {@link MultiResolutionStreamInfo} can also be used
|
||||
* to create a multi-resolution reprocessable camera capture session. See
|
||||
* {@link android.hardware.camera2.params.InputConfiguration} for details.</p>
|
||||
*
|
||||
* @see InputConfiguration
|
||||
* @see android.hardware.camera2.MultiResolutionImageReader
|
||||
*/
|
||||
public class MultiResolutionStreamInfo {
|
||||
private int mStreamWidth;
|
||||
private int mStreamHeight;
|
||||
private String mPhysicalCameraId;
|
||||
|
||||
/**
|
||||
* Create a new {@link MultiResolutionStreamInfo}.
|
||||
*
|
||||
* <p>This class creates a {@link MultiResolutionStreamInfo} using image width, image height,
|
||||
* and the physical camera Id images originate from.</p>
|
||||
*
|
||||
* <p>Normally applications do not need to create these directly. Use {@link
|
||||
* MultiResolutionStreamConfigurationMap#getOutputInfo} or {@link
|
||||
* MultiResolutionStreamConfigurationMap#getInputInfo} to obtain them for a particular format
|
||||
* instead.</p>
|
||||
*/
|
||||
public MultiResolutionStreamInfo(int streamWidth, int streamHeight,
|
||||
@NonNull String physicalCameraId) {
|
||||
mStreamWidth = streamWidth;
|
||||
mStreamHeight = streamHeight;
|
||||
mPhysicalCameraId = physicalCameraId;
|
||||
}
|
||||
|
||||
/**
|
||||
* The width of this particular image buffer stream in pixels.
|
||||
*/
|
||||
public int getWidth() {
|
||||
return mStreamWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* The height of this particular image buffer stream in pixels.
|
||||
*/
|
||||
public int getHeight() {
|
||||
return mStreamHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* The physical camera Id of this particular image buffer stream.
|
||||
*/
|
||||
public @NonNull String getPhysicalCameraId() {
|
||||
return mPhysicalCameraId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this {@link MultiResolutionStreamInfo} is equal to another
|
||||
* {@link MultiResolutionStreamInfo}.
|
||||
*
|
||||
* @return {@code true} if the objects were equal, {@code false} otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof MultiResolutionStreamInfo) {
|
||||
final MultiResolutionStreamInfo other = (MultiResolutionStreamInfo) obj;
|
||||
return mStreamWidth == other.mStreamWidth &&
|
||||
mStreamHeight == other.mStreamHeight &&
|
||||
mPhysicalCameraId.equals(other.mPhysicalCameraId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(
|
||||
mStreamWidth, mStreamHeight, mPhysicalCameraId);
|
||||
}
|
||||
}
|
||||
@@ -24,9 +24,13 @@ import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.graphics.ImageFormat;
|
||||
import android.hardware.camera2.CameraCaptureSession;
|
||||
import android.hardware.camera2.CameraCharacteristics;
|
||||
import android.hardware.camera2.CameraDevice;
|
||||
import android.hardware.camera2.MultiResolutionImageReader;
|
||||
import android.hardware.camera2.params.MultiResolutionStreamInfo;
|
||||
import android.hardware.camera2.utils.HashCodeHelpers;
|
||||
import android.hardware.camera2.utils.SurfaceUtils;
|
||||
import android.media.ImageReader;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.Log;
|
||||
@@ -34,6 +38,7 @@ import android.util.Size;
|
||||
import android.view.Surface;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -81,6 +86,13 @@ import java.util.Objects;
|
||||
* {@link CameraCaptureSession#updateOutputConfiguration} can be called after the configuration
|
||||
* finalize method returns without exceptions.</li>
|
||||
*
|
||||
* <li>If the camera device supports multi-resolution output streams, {@link
|
||||
* CameraCharacteristics#SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP} will contain the
|
||||
* formats and their corresponding stream info. The application can use an OutputConfiguration
|
||||
* created with the multi-resolution stream info queried from {@link
|
||||
* MultiResolutionStreamConfigurationMap#getOutputInfo} and
|
||||
* {@link android.hardware.camera2.MultiResolutionImageReader} to capture variable size images.
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <p> As of {@link android.os.Build.VERSION_CODES#P Android P}, all formats except
|
||||
@@ -88,6 +100,7 @@ import java.util.Objects;
|
||||
* device support. On prior API levels, only {@link ImageFormat#PRIVATE} format may be used.</p>
|
||||
*
|
||||
* @see CameraDevice#createCaptureSessionByOutputConfigurations
|
||||
* @see CameraCharacteristics#SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP
|
||||
*
|
||||
*/
|
||||
public final class OutputConfiguration implements Parcelable {
|
||||
@@ -205,6 +218,33 @@ public final class OutputConfiguration implements Parcelable {
|
||||
this(surfaceGroupId, surface, ROTATION_0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the multi-resolution output flag.
|
||||
*
|
||||
* <p>Specify that this OutputConfiguration is part of a multi-resolution output stream group
|
||||
* used by {@link android.hardware.camera2.MultiResolutionImageReader}.</p>
|
||||
*
|
||||
* <p>This function must only be called for an OutputConfiguration with a non-negative
|
||||
* group ID. And all OutputConfigurations of a MultiResolutionImageReader will have the same
|
||||
* group ID and have this flag set.</p>
|
||||
*
|
||||
* @throws IllegalStateException If surface sharing is enabled via {@link #enableSurfaceSharing}
|
||||
* call, or no non-negative group ID has been set.
|
||||
* @hide
|
||||
*/
|
||||
void setMultiResolutionOutput() {
|
||||
if (mIsShared) {
|
||||
throw new IllegalStateException("Multi-resolution output flag must not be set for " +
|
||||
"configuration with surface sharing");
|
||||
}
|
||||
if (mSurfaceGroupId == SURFACE_GROUP_ID_NONE) {
|
||||
throw new IllegalStateException("Multi-resolution output flag should only be set for " +
|
||||
"surface with non-negative group ID");
|
||||
}
|
||||
|
||||
mIsMultiResolution = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link OutputConfiguration} instance.
|
||||
*
|
||||
@@ -265,6 +305,45 @@ public final class OutputConfiguration implements Parcelable {
|
||||
mIsDeferredConfig = false;
|
||||
mIsShared = false;
|
||||
mPhysicalCameraId = null;
|
||||
mIsMultiResolution = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a list of {@link OutputConfiguration} instances for the outputs used by a
|
||||
* {@link android.hardware.camera2.MultiResolutionImageReader}.
|
||||
*
|
||||
* <p>This constructor takes an argument for a
|
||||
* {@link android.hardware.camera2.MultiResolutionImageReader}.</p>
|
||||
*
|
||||
* @param multiResolutionImageReader
|
||||
* The multi-resolution image reader object.
|
||||
*/
|
||||
public static @NonNull Collection<OutputConfiguration> createInstancesForMultiResolutionOutput(
|
||||
@NonNull MultiResolutionImageReader multiResolutionImageReader) {
|
||||
checkNotNull(multiResolutionImageReader, "Multi-resolution image reader must not be null");
|
||||
|
||||
int groupId = MULTI_RESOLUTION_GROUP_ID_COUNTER;
|
||||
MULTI_RESOLUTION_GROUP_ID_COUNTER++;
|
||||
// Skip in case the group id counter overflows to -1, the invalid value.
|
||||
if (MULTI_RESOLUTION_GROUP_ID_COUNTER == -1) {
|
||||
MULTI_RESOLUTION_GROUP_ID_COUNTER++;
|
||||
}
|
||||
|
||||
ImageReader[] imageReaders = multiResolutionImageReader.getReaders();
|
||||
ArrayList<OutputConfiguration> configs = new ArrayList<OutputConfiguration>();
|
||||
for (int i = 0; i < imageReaders.length; i++) {
|
||||
MultiResolutionStreamInfo streamInfo =
|
||||
multiResolutionImageReader.getStreamInfoForImageReader(imageReaders[i]);
|
||||
|
||||
OutputConfiguration config = new OutputConfiguration(
|
||||
groupId, imageReaders[i].getSurface());
|
||||
config.setPhysicalCameraId(streamInfo.getPhysicalCameraId());
|
||||
config.setMultiResolutionOutput();
|
||||
configs.add(config);
|
||||
// TODO: Set sensor pixel mode for ultra high resolution sensor camera.
|
||||
}
|
||||
|
||||
return configs;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -319,6 +398,7 @@ public final class OutputConfiguration implements Parcelable {
|
||||
mIsDeferredConfig = true;
|
||||
mIsShared = false;
|
||||
mPhysicalCameraId = null;
|
||||
mIsMultiResolution = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -355,8 +435,18 @@ public final class OutputConfiguration implements Parcelable {
|
||||
* <p>Up to {@link #getMaxSharedSurfaceCount} surfaces can be shared for an OutputConfiguration.
|
||||
* The supported surfaces for sharing must be of type SurfaceTexture, SurfaceView,
|
||||
* MediaRecorder, MediaCodec, or implementation defined ImageReader.</p>
|
||||
*
|
||||
* <p>This function must not be called from OuptutConfigurations created by {@link
|
||||
* #createInstancesForMultiResolutionOutput}.</p>
|
||||
*
|
||||
* @throws IllegalStateException If this OutputConfiguration is created via {@link
|
||||
* #createInstancesForMultiResolutionOutput} to back a MultiResolutionImageReader.
|
||||
*/
|
||||
public void enableSurfaceSharing() {
|
||||
if (mIsMultiResolution) {
|
||||
throw new IllegalStateException("Cannot enable surface sharing on "
|
||||
+ "multi-resolution output configurations");
|
||||
}
|
||||
mIsShared = true;
|
||||
}
|
||||
|
||||
@@ -368,8 +458,7 @@ public final class OutputConfiguration implements Parcelable {
|
||||
* This call achieves it by mapping the OutputConfiguration to the physical camera id.</p>
|
||||
*
|
||||
* <p>The valid physical camera ids can be queried by {@link
|
||||
* android.hardware.camera2.CameraCharacteristics#getPhysicalCameraIds}.
|
||||
* </p>
|
||||
* CameraCharacteristics#getPhysicalCameraIds}.</p>
|
||||
*
|
||||
* <p>Passing in a null physicalCameraId means that the OutputConfiguration is for a logical
|
||||
* stream.</p>
|
||||
@@ -380,8 +469,16 @@ public final class OutputConfiguration implements Parcelable {
|
||||
* after {@link CameraDevice#createCaptureSessionByOutputConfigurations} or {@link
|
||||
* CameraDevice#createReprocessableCaptureSessionByConfigurations} has no effect.</p>
|
||||
*
|
||||
* <p>The surface belonging to a physical camera OutputConfiguration must not be used as input
|
||||
* or output of a reprocessing request. </p>
|
||||
* <p>As of {@link android.os.Build.VERSION_CODES#S Android 12}, an image buffer from a
|
||||
* physical camera stream can be used for reprocessing to logical camera streams and streams
|
||||
* from the same physical camera if the camera device supports multi-resolution input and output
|
||||
* streams. See {@link CameraCharacteristics#SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP}
|
||||
* for details. The behaviors of reprocessing from a non-physical camera stream to a physical
|
||||
* camera stream, and from a physical camera stream to a physical camera stream of different
|
||||
* physical camera, are device-specific and not guaranteed to be supported.</p>
|
||||
*
|
||||
* <p>On prior API levels, the surface belonging to a physical camera OutputConfiguration must
|
||||
* not be used as input or output of a reprocessing request. </p>
|
||||
*/
|
||||
public void setPhysicalCameraId(@Nullable String physicalCameraId) {
|
||||
mPhysicalCameraId = physicalCameraId;
|
||||
@@ -527,6 +624,7 @@ public final class OutputConfiguration implements Parcelable {
|
||||
this.mIsDeferredConfig = other.mIsDeferredConfig;
|
||||
this.mIsShared = other.mIsShared;
|
||||
this.mPhysicalCameraId = other.mPhysicalCameraId;
|
||||
this.mIsMultiResolution = other.mIsMultiResolution;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -543,6 +641,7 @@ public final class OutputConfiguration implements Parcelable {
|
||||
ArrayList<Surface> surfaces = new ArrayList<Surface>();
|
||||
source.readTypedList(surfaces, Surface.CREATOR);
|
||||
String physicalCameraId = source.readString();
|
||||
boolean isMultiResolutionOutput = source.readInt() == 1;
|
||||
|
||||
checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
|
||||
|
||||
@@ -566,6 +665,7 @@ public final class OutputConfiguration implements Parcelable {
|
||||
mConfiguredGenerationId = 0;
|
||||
}
|
||||
mPhysicalCameraId = physicalCameraId;
|
||||
mIsMultiResolution = isMultiResolutionOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -665,6 +765,7 @@ public final class OutputConfiguration implements Parcelable {
|
||||
dest.writeInt(mIsShared ? 1 : 0);
|
||||
dest.writeTypedList(mSurfaces);
|
||||
dest.writeString(mPhysicalCameraId);
|
||||
dest.writeInt(mIsMultiResolution ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -694,7 +795,8 @@ public final class OutputConfiguration implements Parcelable {
|
||||
mConfiguredFormat != other.mConfiguredFormat ||
|
||||
mConfiguredDataspace != other.mConfiguredDataspace ||
|
||||
mConfiguredGenerationId != other.mConfiguredGenerationId ||
|
||||
!Objects.equals(mPhysicalCameraId, other.mPhysicalCameraId))
|
||||
!Objects.equals(mPhysicalCameraId, other.mPhysicalCameraId) ||
|
||||
mIsMultiResolution != other.mIsMultiResolution)
|
||||
return false;
|
||||
|
||||
int minLen = Math.min(mSurfaces.size(), other.mSurfaces.size());
|
||||
@@ -720,17 +822,24 @@ public final class OutputConfiguration implements Parcelable {
|
||||
return HashCodeHelpers.hashCode(
|
||||
mRotation, mConfiguredSize.hashCode(), mConfiguredFormat, mConfiguredDataspace,
|
||||
mSurfaceGroupId, mSurfaceType, mIsShared ? 1 : 0,
|
||||
mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode());
|
||||
mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode(),
|
||||
mIsMultiResolution ? 1 : 0);
|
||||
}
|
||||
|
||||
return HashCodeHelpers.hashCode(
|
||||
mRotation, mSurfaces.hashCode(), mConfiguredGenerationId,
|
||||
mConfiguredSize.hashCode(), mConfiguredFormat,
|
||||
mConfiguredDataspace, mSurfaceGroupId, mIsShared ? 1 : 0,
|
||||
mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode());
|
||||
mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode(),
|
||||
mIsMultiResolution ? 1 : 0);
|
||||
}
|
||||
|
||||
private static final String TAG = "OutputConfiguration";
|
||||
|
||||
// A surfaceGroupId counter used for MultiResolutionImageReader. Its value is
|
||||
// incremented everytime {@link createInstancesForMultiResolutionOutput} is called.
|
||||
private static int MULTI_RESOLUTION_GROUP_ID_COUNTER = 0;
|
||||
|
||||
private ArrayList<Surface> mSurfaces;
|
||||
private final int mRotation;
|
||||
private final int mSurfaceGroupId;
|
||||
@@ -749,4 +858,7 @@ public final class OutputConfiguration implements Parcelable {
|
||||
private boolean mIsShared;
|
||||
// The physical camera id that this output configuration is for.
|
||||
private String mPhysicalCameraId;
|
||||
// Flag indicating if this config is for a multi-resolution output with a
|
||||
// MultiResolutionImageReader
|
||||
private boolean mIsMultiResolution;
|
||||
}
|
||||
|
||||
@@ -130,11 +130,13 @@ public final class SessionConfiguration implements Parcelable {
|
||||
int inputWidth = source.readInt();
|
||||
int inputHeight = source.readInt();
|
||||
int inputFormat = source.readInt();
|
||||
boolean isInputMultiResolution = source.readBoolean();
|
||||
ArrayList<OutputConfiguration> outConfigs = new ArrayList<OutputConfiguration>();
|
||||
source.readTypedList(outConfigs, OutputConfiguration.CREATOR);
|
||||
|
||||
if ((inputWidth > 0) && (inputHeight > 0) && (inputFormat != -1)) {
|
||||
mInputConfig = new InputConfiguration(inputWidth, inputHeight, inputFormat);
|
||||
mInputConfig = new InputConfiguration(inputWidth, inputHeight,
|
||||
inputFormat, isInputMultiResolution);
|
||||
}
|
||||
mSessionType = sessionType;
|
||||
mOutputConfigurations = outConfigs;
|
||||
@@ -169,10 +171,12 @@ public final class SessionConfiguration implements Parcelable {
|
||||
dest.writeInt(mInputConfig.getWidth());
|
||||
dest.writeInt(mInputConfig.getHeight());
|
||||
dest.writeInt(mInputConfig.getFormat());
|
||||
dest.writeBoolean(mInputConfig.isMultiResolution());
|
||||
} else {
|
||||
dest.writeInt(/*inputWidth*/ 0);
|
||||
dest.writeInt(/*inputHeight*/ 0);
|
||||
dest.writeInt(/*inputFormat*/ -1);
|
||||
dest.writeBoolean(/*isMultiResolution*/ false);
|
||||
}
|
||||
dest.writeTypedList(mOutputConfigurations);
|
||||
}
|
||||
|
||||
@@ -1575,7 +1575,7 @@ public final class StreamConfigurationMap {
|
||||
return sizes;
|
||||
}
|
||||
|
||||
/** Get the list of publically visible output formats; does not include IMPL_DEFINED */
|
||||
/** Get the list of publicly visible output formats */
|
||||
private int[] getPublicFormats(boolean output) {
|
||||
int[] formats = new int[getPublicFormatCount(output)];
|
||||
|
||||
@@ -1746,6 +1746,21 @@ public final class StreamConfigurationMap {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Size comparison method used by size comparators.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static int compareSizes(int widthA, int heightA, int widthB, int heightB) {
|
||||
long left = widthA * (long) heightA;
|
||||
long right = widthB * (long) heightB;
|
||||
if (left == right) {
|
||||
left = widthA;
|
||||
right = widthB;
|
||||
}
|
||||
return (left < right) ? -1 : (left > right ? 1 : 0);
|
||||
}
|
||||
|
||||
private void appendOutputsString(StringBuilder sb) {
|
||||
sb.append("Outputs(");
|
||||
int[] formats = getOutputFormats();
|
||||
@@ -1843,7 +1858,10 @@ public final class StreamConfigurationMap {
|
||||
sb.append(")");
|
||||
}
|
||||
|
||||
private String formatToString(int format) {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static String formatToString(int format) {
|
||||
switch (format) {
|
||||
case ImageFormat.YV12:
|
||||
return "YV12";
|
||||
|
||||
Reference in New Issue
Block a user